密码与密钥管理规范
密码存储、密钥轮换
[Requirement] 用户密码必须使用不可逆哈希存储,禁止明文、禁止可逆加密。
| 算法 | 是否推荐 | 说明 |
|---|---|---|
| Argon2id | 推荐(首选) | 抗 GPU 暴力破解,可调内存/时间参数 |
| bcrypt | 推荐 | 成熟稳定,内置盐值,work factor 可调 |
| scrypt | 可选 | 内存难函数,抗 ASIC |
| SHA-256 + 盐 | 不推荐 | 速度太快,易被 GPU 暴力破解 |
| MD5 / SHA-1 | 禁止 | 已被破解,不安全 |
[Standard] 推荐使用 Argon2id,参数:内存 64MB、迭代 3 次、并行度 4;或 bcrypt,cost factor ≥ 12。
[Requirement] 每个密码使用独立随机盐(≥ 16 字节),盐与哈希值一起存储,禁止全局共用一个盐。
[Standard] bcrypt / Argon2 内部已自动生成并存储盐,无需手动处理。
# bcrypt 示例
import bcrypt
def hash_password(password: str) -> str:
salt = bcrypt.gensalt(rounds=12)
hashed = bcrypt.hashpw(password.encode(), salt)
return hashed.decode()
def verify_password(password: str, hashed: str) -> bool:
return bcrypt.checkpw(password.encode(), hashed.encode())# Argon2 示例
from argon2 import PasswordHasher
ph = PasswordHasher(time_cost=3, memory_cost=65536, parallelism=4)
def hash_password(password: str) -> str:
return ph.hash(password)
def verify_password(password: str, hashed: str) -> bool:
try:
return ph.verify(hashed, password)
except Exception:
return False[Standard] 密码长度 ≥ 8 位,建议包含大小写字母、数字、特殊字符中至少 3 种;禁止弱密码(如 123456、password、连续/重复字符)。
[Caution] 不要强制定期改密码(NIST 已不建议),改为检测是否出现在泄露密码库(HIBP)中。
[Requirement] 密码哈希比较使用恒定时间比较(bcrypt/argon2 库内置),禁止用 == 比对哈希字符串,防止时序攻击。
| 密钥类型 | 示例 | 存储方式 | 访问方式 |
|---|---|---|---|
| 主密钥(KEK) | 加密数据密钥的根密钥 | KMS / HSM,永不离开硬件 | 通过 KMS API 调用 |
| 数据密钥(DEK) | 加密业务数据的密钥 | 加密后存数据库 / 配置 | 由 KEK 解密后使用 |
| 应用密钥 | AppSecret、API Key | 加密存配置中心 / 环境变量 | 运行时解密 |
| 签名密钥 | JWT 签名密钥、HMAC 密钥 | KMS / 加密配置 | 运行时加载 |
[Requirement] 禁止把密钥硬编码在代码、Git 仓库、Docker 镜像中;必须通过环境变量、配置中心(加密)或 KMS 注入。
[Requirement] 生产环境密钥存储于 KMS(如 AWS KMS、阿里云 KMS、HashiCorp Vault)或 HSM,开发/测试环境用本地加密配置文件(如 .env 加 .gitignore)。
[Standard] 密钥按环境隔离(dev / staging / prod 不同密钥),禁止跨环境复用。
# 配置中心加密配置示例(密钥由 KMS 加密后存储)
database:
host: db.prod.internal
username: app_user
password: ENC(AWSCiphertextBlob:AQICAHg...) # KMS 加密后的密文
jwt:
secret: ENC(vault:secret/jwt/prod)[Standard] 应用通过 IAM 角色 / 服务身份从 KMS 获取密钥,密钥不落盘到应用容器,仅在内存中使用。
[Caution] 禁止在日志、异常堆栈、错误信息中输出密钥。
| 密钥类型 | 轮换周期 | 方式 |
|---|---|---|
| JWT 签名密钥 | 90 天 | 新旧密钥并存一段时间,平滑过渡 |
| AppSecret / API Key | 90~180 天 | 生成新密钥 → 双写 → 切换 → 旧密钥过期 |
| 数据加密密钥(DEK) | 180 天 | 重新加密数据(re-encrypt) |
| 主密钥(KEK) | 1 年 | KMS 自动轮换 |
| TLS 证书 | 90 天(Let’s Encrypt) | 自动续期 |
[Standard] 密钥轮换采用双密钥并行策略:新密钥生效后,旧密钥保留一段时间(一般 1 个轮换周期)用于兼容,确认无流量后再废弃。
1. 生成新密钥并存入 KMS2. 配置新密钥为"生效中",旧密钥为"待废弃"3. 应用同时支持新旧密钥(读取时依次尝试)4. 监控旧密钥使用量,降为 0 后标记为"废弃"5. 废弃密钥保留 30 天备查,然后彻底删除[Requirement] 发生密钥泄露事件时,立即触发应急轮换:生成新密钥 → 配置生效 → 旧密钥立即失效(不保留并行期)→ 审计影响范围。
[Requirement] 密钥访问遵循最小权限原则:只有需要解密的服务才能调用 KMS 解密,其他服务只能加密(或完全无权限)。
[Standard] KMS 密钥策略限制:哪些 IAM 角色可以 Decrypt、哪些可以 Encrypt、哪些可以管理密钥。
[Requirement] 禁止开发人员直接访问生产密钥;如需查看,走审批流程,通过临时凭证访问并记录审计日志。
[Caution] 禁止在 IM、邮件、文档中传递生产密钥;密钥传递使用一次性加密链接(如 1Password、Vault)。
[Requirement] CI 流水线集成密钥扫描工具(如 gitleaks、trufflehog、detect-secrets),阻止包含密钥的代码提交。
# gitleaks 扫描示例
gitleaks detect --source . --redact --verbose[Requirement] 如发现密钥已提交到 Git,必须立即轮换该密钥,并清理 Git 历史(git filter-repo 或 BFG)。
[Requirement] KMS 的所有密钥操作(Create、Encrypt、Decrypt、Rotate、Disable)必须记录审计日志,保留 ≥ 1 年。
[Standard] 审计日志包含:操作时间、操作者(IAM 主体)、操作类型、密钥 ID、调用来源 IP、结果。
[Standard] 对以下行为触发告警:
- 非工作时间的密钥访问
- 大量解密操作(可能是批量窃取数据)
- 密钥管理操作(创建、删除、轮换)
- 来自非常规 IP 的访问
[Requirement] 密码修改、重置、登录失败等操作记录审计日志,包含用户 ID、时间、IP、结果,便于事后追溯。
[Caution] 审计日志中禁止记录密码明文或哈希值。