3. 踩坑二:加密算法选择不当 - 使用已淘汰算法
这个问题说起来挺尴尬的。我在一次代码审计中,发现某个核心业务字段居然还在用 DES 加密。问团队为什么选这个,回答是「以前一直这么用的,没出过事」。嗯,这句话本身就是最大的风险。
加密算法选错了,就等于你家大门装了一把三十年前的锁。锁没坏,但小偷手里的工具早就升级了。今天我们就来盘一盘,哪些算法已经不能用了,以及你为什么不能随手复制网上的老代码。
3.1 已淘汰算法清单
我个人习惯把算法分为三档:禁用、不推荐、安全。下面这张表可以直接贴在团队的 Wiki 里。
| 分类 | 算法 | 密钥长度 | 淘汰原因 | 替代方案 |
|---|---|---|---|---|
| 禁用 | DES | 56 位 | 穷举攻击可在 24 小时内破解 | AES-256 |
| 禁用 | MD2 / MD4 / MD5 | —— | 碰撞攻击成本极低(2004 年已演示) | SHA-256 / SHA-3 |
| 禁用 | RC4 | 可变 | 偏差暴露明文,TLS 已禁用 | ChaCha20 / AES-GCM |
| 不推荐 | 3DES (TDEA) | 112 位有效 | 速度慢,Sweet32 攻击可用 | AES-256 |
| 不推荐 | RSA-1024 | 1024 位 | NIST 建议 2048 位以上 | RSA-3072 / ECDSA |
| 不推荐 | SHA-1 | 160 位 | Google 已展示 SHAttered 碰撞 | SHA-256 / SHA-384 |
⚠️ 警告: 千万别觉得「3DES 比 DES 多了两轮就安全」。我见过一个项目把 3DES 当金标准,结果被 Sweet32 攻击打得措手不及。说白了,大部分已淘汰算法的缺陷都是公开的 CVE,不是理论问题,是实战问题。
3.2 为什么人们还在用已淘汰算法?
我在项目中遇到过三次类似情况,原因惊人一致:
- 历史遗留 —— 数据库里存的老密文没法一次性迁移,新老代码混着跑。
- 「能用就别动」心态 —— 产品经理说改密码算法要停服,不敢改。
- 复制粘贴灾难 —— 从 Stack Overflow 或者十年前的博客直接抄代码,没看日期。
你想想看,2017 年之后开源的加密库基本都把 DES 和 MD5 标为废弃了。如果你还在用,要么是没升级库,要么是主动绕过了警告。后者更危险——我在代码审查里见过有人特意用 @SuppressWarnings 压掉 IDE 的过期提醒。这不是在解决问题,是在埋雷。
3.3 字段级加密的算法选型原则
字段级加密跟传输层加密不一样。传输层可以用临时密钥协商,字段加密往往是静态的,密文要存很久。所以选算法时,我一般会问自己三个问题:
- 未来五年会不会被破解? —— 选 AES-256 或 ChaCha20,当前没有已知有效攻击。
- 有没有行业标准背书? —— 比如 FIPS 140-3 认证的算法,或者 NIST 推荐。
- 密钥怎么管理? —— 算法再强,密钥硬编码在代码里也是白搭。这个后面会单独讲。
💡 我的习惯: 对于字段级对称加密,直接锁定
AES-256-GCM。记得加关联数据(AAD),防止篡改。别用 ECB 模式——它会把相同的明文块加密成相同的密文块,等于把结构暴露给攻击者。
3.4 代码示例:从 MD5 迁移到 SHA-256
假设你原来用 MD5 哈希银行卡号(别笑,我真见过)。现在的做法应该是 HMAC-SHA256 加盐。下面是伪代码思路:
// ❌ 旧做法:MD5 裸哈希(不要用!)
String hash = DigestUtils.md5Hex(cardNumber);
// 问题:无盐,可查彩虹表,碰撞极易构造
// ✅ 新做法:HMAC-SHA256 + 随机盐
byte[] salt = generateRandomSalt(16);
// 每个字段单独盐,不可复用
Mac hmac = Mac.getInstance("HmacSHA256");
SecretKeySpec key = new SecretKeySpec(masterKey, "HmacSHA256");
hmac.init(key);
byte[] hashBytes = hmac.doFinal(cardNumber.getBytes(StandardCharsets.UTF_8));
String hash = Base64.getEncoder().encodeToString(hashBytes);
// 存储时把盐也保存(明文),用于验证权重
这里有个坑:盐必须随机且独立。我曾经看到有人把系统启动时间当盐……同一个时间段写入的数据全部一个盐,那跟没加没什么区别。
3.5 一张图理清算法选择逻辑
下面这张流程图画的是我个人做算法决策时的判断路径。每次选加密方案,我都会走一遍。
3.6 避坑指南
- 不要迷信「自定义加密算法」 —— 我见过一个团队自己发明了一个异或+移位算法,号称比 AES 快。结果内部测试不到 10 分钟就被我同事用线性分析推出来了。自己写密码学等于把自己当全世界的攻击者的靶子。
- 不要用同一个密钥加密所有字段 —— 如果每个字段都使用不同的派生密钥(通过主密钥 + 字段标识 + 盐生成),一个字段泄露不会波及其他字段。
- 曾经有个项目把 RSA 私钥明文写在 GitHub 上 —— 虽然这是配置管理的问题,但如果你选错了算法,连被破解的机会都省了。
总结一句话: 算法选型不是靠记忆,是靠清单。每次项目开始前,拿上面那张表过一遍,比事后修漏洞省太多成本。