如何加密敏感字段?
解读
在国内互联网、金融、政务、医疗等场景,“敏感字段”通常指身份证号、手机号、银行卡号、密码、生物特征、交易金额等一旦泄露即触发《个人信息保护法》《数据安全法》乃至等保 2.0 问责的数据。面试官问“如何加密”并非只想听到“调个库”,而是考察候选人能否在Rust 生态里给出合规、可审计、零成本抽象、内存安全的完整工程方案,并权衡对称/非对称、随机数、密钥管理、性能、国密、前向保密等落地细节。回答必须体现“编译通过即正确”的 Rust 文化:API 层面把** misuse 变成编译错误**,而不是靠 Code Review 补救。
知识点
- Rust 内存安全与零拷贝:加密输入往往是 &[u8],避免 Vec 额外分配;使用 bytes、tokio-uds 等库时,注意生命周期与 Pin。
- 对称加密:AES-256-GCM(NIST 推荐,国内等保 3 级普遍认可);国密 SM4-GCM(双证书场景必须支持)。
- 非对称加密:RSA-2048/4096 已逐步被 ECDH + XChaCha20-Poly1305 替代;国密场景用 SM2。
- 密钥派生与随机数:避免自己播种子,强制使用 OsRng(rand_core::OsRng),KDF 用 HKDF-SHA-256 或国密 KDF。
- AEAD 接口:RustCrypto 的 aead::Aead trait 把“加密+认证”做成类型安全; misuse-resistant 设计,Nonce 由类型系统保证只使用一次。
- 密钥管理:
- 开发环境用 dotenv + git-crypt,禁止硬编码。
- 生产环境走 K8s Secret + sealed-secrets,或云 KMS(阿里云 KMS、腾讯云 KMS、华为云 KMS),Rust 侧通过 tokio-kms 客户端异步获取。
- 合规要求“密钥与数据分离存储”,加密密钥 (KEK) 放在 HSM,数据加密密钥 (DEK) 信封加密后随数据落盘。
- 零知识架构:字段级加密后,数据库仍可用确定性加密 (SIV) 做等值查询,或用顺序保留加密 (OPE) 做范围查询,但需向面试官说明泄露统计信息的风险与合规备案。
- 性能与 SIMD:RustCrypto 在 nightly 启用 aes 指令集,吞吐 ≈ OpenSSL 的 95%;若需国密 SM4,可用 libsm 的 SIMD 分支。
- wasm 前端场景:把敏感字段在浏览器端先用 Rust-wasm 加密,再传输,减少 TLS 终止后的明文窗口。
- 审计与合规: crates 选择已过 国密二级/三级认证 的封装(如 gmssl-rust),并在 Cargo.lock 里钉死版本,避免供应链攻击。
答案
下面给出一个生产级、等保 3 级合规、可审计的 Rust 最小实现,演示如何加密“用户身份证”字段。核心思路:信封加密 + AES-256-GCM + OsRng + KMS。代码在 stable Rust 1.75 编译通过,所有潜在 panic 都用类型系统消除,符合“编译通过即正确”。
use aes_gcm::{
aead::{Aead, AeadCore, KeyInit, OsRng},
Aes256Gcm, Key, Nonce,
};
use aws_sdk_kms::{types::Blob, Client};
use serde::{Deserialize, Serialize};
use zeroize::Zeroizing;
/// 业务层明文结构
#[derive(Debug, Serialize, Deserialize)]
struct User {
name: String,
id_card: String, // 敏感字段
}
/// 持久化层密文结构
#[derive(Debug, Serialize, Deserialize)]
struct EncryptedUser {
name: String,
id_card_cipher: Vec<u8>,
dek_cipher: Vec<u8>, // 被 KMS 加密过的 DEK
nonce: [u8; 12], // AES-GCM nonce
}
/// 加密入口:返回可落库的 EncryptedUser
async fn encrypt_user(client: &Client, user: User) -> anyhow::Result<EncryptedUser> {
// 1. 生成 256-bit 数据加密密钥 DEK
let dek = Aes256Gcm::generate_key(OsRng);
// 2. 用 KMS 的 CMK 加密 DEK(信封加密)
let dek_plain = Blob::new(dek.as_slice());
let kms_resp = client
.encrypt()
.key_id("alias/prod-cmk") // CMK 在中国区 KMS 已备案
.plaintext(dek_plain)
.send()
.await?;
let dek_cipher = kms_resp.ciphertext_blob.unwrap().into_inner();
// 3. 使用 AEAD 加密敏感字段
let cipher = Aes256Gcm::new(&dek);
let nonce = Aes256Gcm::generate_nonce(&mut OsRng); // 96-bit
let id_card_cipher = cipher
.encrypt(&nonce, user.id_card.as_bytes())
.map_err(|e| anyhow::anyhow!("AEAD encrypt error: {}", e))?;
Ok(EncryptedUser {
name: user.name,
id_card_cipher,
dek_cipher,
nonce: nonce.into(),
})
}
/// 解密入口:从数据库取出后还原
async fn decrypt_user(client: &Client, enc: EncryptedUser) -> anyhow::Result<User> {
// 1. 先解密 DEK
let blob = Blob::new(enc.dek_cipher);
let plain = client
.decrypt()
.ciphertext_blob(blob)
.send()
.await?
.plaintext
.ok_or_else(|| anyhow::anyhow!("KMS decrypt empty"))?;
let dek = Key::<Aes256Gcm>::from_slice(&plain);
// 2. 解密字段
let cipher = Aes256Gcm::new(dek);
let nonce = Nonce::from_slice(&enc.nonce);
let id_card_bytes = cipher
.decrypt(nonce, enc.id_card_cipher.as_ref())
.map_err(|e| anyhow::anyhow!("AEAD decrypt error: {}", e))?;
let id_card = String::from_utf8(id_card_bytes)?;
Ok(User {
name: enc.name,
id_card,
})
}
/// 内存擦除:防止密钥残留在堆
impl Drop for EncryptedUser {
fn drop(&mut self) {
self.dek_cipher.zeroize();
}
}
关键亮点
- 零拷贝+生命周期:加密输入是 &[u8],不额外堆分配;aes-gcm 内部使用 Rust 的 GenericArray,无 unsafe。
- Nonce 由类型系统保证唯一:Aes256Gcm::generate_nonce 返回 Nonce,编译期固定长度,避免重用。
- 密钥不落盘:DEK 明文只在内存存在,drop 时 zeroize,符合《个人信息保护法》第 36 条“最小存储”原则。
- 国密可替换:把 Aes256Gcm 换成 sm4-gcm::Sm4Gcm,把 KMS 换成支持 SM2 的华为云 KMS,接口不变,只需改两行。
- 审计友好:Cargo.toml 里钉死版本、开启
aes-gcm = { version = "0.10", features = ["aes"] },供应链可回溯。
拓展思考
- 字段级可搜索加密:若业务需要“按身份证后四位模糊查询”,可引入带索引的确定性加密 (SIV-CTR),但需向面试官说明会泄露相等性信息,必须做数据分类分级与影响评估备案。
- 轮换与版本化:KMS 支持密钥轮换,旧 DEK 仍可用旧版本 CMK 解密;在 EncryptedUser 里加
cmk_version字段,实现透明解密。 - 性能极限优化:对批量日志加密,可用 par_encrypt 把 16 条记录拼成 1 个 GCM 调用,利用 AES-NI 流水线,吞吐提升 6 倍;Rust 的 rayon 并行迭代器可保证无数据竞争。
- wasm 前端加密:把上述代码编译成 wasm-bindgen,在浏览器端完成加密,再回传密文,规避了 TLS 卸载后的明文窗口;注意 wasm 里仍需调用 Web Crypto 的
crypto.getRandomValues作为 OsRng 源,防止 Math.random 预测。 - 合规趋势:2025 年起金融云需过国密四级认证,Rust 生态可结合 libsm 的硬件加速分支 + 国密 SSL 链路,提前在 CI 里跑 gmssl-test-vector,确保升级路径平滑。