题目4 私钥存储安全:文件系统、数据库、密钥库
私钥一旦泄露,整个SM2体系就等于废了。我见过太多因为存储环节出问题的案例——权限没设好、备份文件没加密、数据库被拖库……说白了,存储安全是密钥生命周期里最容易被忽视,但后果最严重的环节。这一章咱们就聊聊几种常见的存储方式,以及该怎么巡检。
文件系统存储
这是最常见也最容易出问题的方式。很多团队直接把私钥文件丢在项目目录下,权限是755甚至777。我记得有个项目,运维图省事,把SM2私钥放在/etc/ssl/private/,结果目录权限是drwxr-xr-x,任何人都能读文件。后来被安全扫描扫出来,紧急整改。
文件系统存储的核心风险有三个:
- 权限失控: 私钥文件必须设置为
400(仅属主可读)或600(属主可读写)。运行SM2程序的用户必须单独创建,不能复用nginx、mysql等高权限账号。 - 明文落盘: 很多开发者直接把PEM格式的私钥字符串写死在配置里。这等于把钥匙挂在门上。至少要用
openssl enc -aes-256-cbc加密后再存,运行时在内存中解密。 - 备份泄露: 备份脚本经常把整个
/etc或/opt目录打包,私钥跟着一起被丢到NAS或云存储。我曾经审计过一个客户,他们的备份文件权限是644,任何人拿到备份就能得到所有SM2私钥。
- 检查所有私钥文件的
ls -l权限,确保≤600。 - 检查私钥文件所在的上级目录权限,不能是
777。 - 检查备份脚本和备份存储位置,私钥不能出现在未加密的备份包中。
数据库存储
把私钥塞进数据库?说实话,我劝你千万别这么干。但现实中确实有人这么做——把私钥作为varchar(2048)字段存到MySQL里。你觉得安全?SQL注入、数据库备份泄露、慢查询日志写入……任何一处出问题,私钥就裸奔了。
如果一定要用数据库存储,必须满足以下条件:
- 加密存储: 不能存明文。使用数据库自带的
AES_ENCRYPT()或应用层先加密再存。密钥管理另用一个独立系统。 - 访问隔离: 即使是DBA,也不能通过
SELECT *直接看到私钥。可以通过数据库的列级加密、权限控制,或者使用视图只返回脱敏信息。 - 审计日志: 谁在什么时间访问了私钥列,必须有记录。我见过一个案例,开发用
UPDATE语句批量改了私钥字段,结果生产环境全部瘫痪。
private_key,然后整个数据库没设任何访问密码就被暴露到公网。扫到后我直接指导他们销毁所有私钥,重新生成。存储方案必须和开发、运维讲清楚:数据库不是密钥保险箱。
密钥库(HSM / TPM / KeyStore)
这才是专业做法。硬件安全模块(HSM)、可信平台模块(TPM)、Java KeyStore、PKCS#11接口的软件令牌,这些才是SM2私钥该待的地方。为什么?因为私钥一旦生成,永远不能离开密钥库——签名运算在密钥库内部完成,外界只能拿到结果,拿不到私钥本身。
| 存储方案 | 安全等级 | 性能 | 成本 | 典型场景 |
|---|---|---|---|---|
| 文件系统(明文) | 低 | 高 | 无 | 临时测试,不可用于生产 |
| 文件系统(加密) | 中 | 高 | 低 | 小型业务,需配合内存解密 |
| 数据库(加密存储) | 中 | 中 | 低 | 多应用共享密钥时考虑 |
| 软件KeyStore(PKCS#12/JKS) | 中高 | 中 | 无 | Java生态、微服务 |
| HSM / TPM | 极高 | 低(硬件加密) | 高 | 金融、政务、关键基础设施 |
我个人偏好是:能用HSM就用HSM,哪怕买个便宜的云HSM也行。如果预算有限,至少用pkcs11-tool配合软令牌(比如SoftHSMv2),把私钥导入令牌后,应用代码通过PKCS#11接口调用签名,私钥永远不出令牌。我帮一个支付系统做过这样的改造,之后安全审计直接过了。
- 如果使用Java KeyStore,请使用
PKCS12格式而非JKS,密码强度至少16位以上。 - HSM一定要开启双人控制(Dual Control)——管理员和操作员分开,私钥导出需要两人同时在场。
- 定期做密钥轮换测试:能不能在不影响业务的情况下生成新私钥并废弃旧私钥?如果做不到,说明密钥库架构有问题。
存储安全巡检清单
巡检不光是看配置,还要动手验证。下面是我自己常用的检查步骤,你可以在巡检时照着做:
- 列出所有SM2私钥文件(找
*.pem、*.key、keystore等),检查权限。 - 检查进程内存:用
gdb -p或procmem查看SM2签名服务进程的内存中是否有私钥明文(正常情况不应有)。 - 检查数据库表字段:看是否有存储私钥但没有加密的列(
SELECT * FROM information_schema.columns)。 - 检查HSM/KeyStore的访问日志:是否有非授权尝试?是否有异常时间段的导出请求?
- 模拟备份恢复:从备份中能否轻松拿到私钥?如果能,说明备份方案不合格。
最后再啰嗦一句:私钥存储不是「选一个就行」,而是要根据业务场景做风险权衡。别因为怕麻烦就选最简单的明文文件存储——等到被通报了再改,代价就大了。我每年都会在自己的系统上跑一遍巡检脚本,把存储安全这件事当成例行公事,而不是出事后补救的措施。