数据加密
规则
- 全面实施 TLS:将 HTTP 重定向到 HTTPS,设置 HSTS 头,绝不允许未加密的连接
- 在存储到数据库之前,在应用层使用 AES-256-GCM 加密 PII 列
- 使用 SHA-256 对电子邮件进行哈希以便查询,使用 AES-256-GCM 加密以便显示 —— 支持搜索而无需暴露数据
- 密码:仅限 bcrypt 或 argon2id —— 绝不使用 SHA、MD5 或可逆加密
- 加密数据库备份,并将加密密钥与数据分开存储
- 浏览器端加密使用
crypto.subtle,服务器端加密使用 node:crypto
- 将加密密钥存储在密钥管理器中,切勿存储在代码中或与加密数据放在一起
import { createCipheriv, createDecipheriv, randomBytes } from "node:crypto";
const ENCRYPTION_KEY = Buffer.from(process.env.ENCRYPTION_KEY!, "hex");
function encrypt(plaintext: string): string {
const iv = randomBytes(12);
const cipher = createCipheriv("aes-256-gcm", ENCRYPTION_KEY, iv);
const encrypted = Buffer.concat([cipher.update(plaintext, "utf8"), cipher.final()]);
const tag = cipher.getAuthTag();
return Buffer.concat([iv, tag, encrypted]).toString("base64");
}
function decrypt(ciphertext: string): string {
const buf = Buffer.from(ciphertext, "base64");
const iv = buf.subarray(0, 12);
const tag = buf.subarray(12, 28);
const encrypted = buf.subarray(28);
const decipher = createDecipheriv("aes-256-gcm", ENCRYPTION_KEY, iv);
decipher.setAuthTag(tag);
return decipher.update(encrypted) + decipher.final("utf8");
}
避免
- 以明文形式存储 PII —— 一旦数据库泄露,所有数据将暴露无遗
- 使用 ECB 模式或无认证的 AES(CBC 无 HMAC)—— 请使用 GCM
- 使用 MD5 或 SHA 进行密码哈希 —— 它们不是密码哈希算法
- 在源代码中硬编码加密密钥 —— 请使用环境变量或 KMS
- 通过 HTTP 发送敏感数据,即使在内部也是如此 —— 对所有连接使用 TLS