3. 加密算法选型原则:安全性、性能、兼容性
做接口加密这么多年,我经常被问到同一个问题:“选哪个算法最好?”
说实话,这个问题没有标准答案。没有最好的算法,只有最合适的算法。
我见过不少团队,一上来就选 AES-256,觉得位数越高越安全。结果呢?在低端 IoT 设备上跑得比乌龟还慢,用户全跑了。我也见过为了追求极致性能,选了个过时的 RC4,结果被安全审计打了个大红叉。
所以选型这事,得有个章法。我个人习惯从三个维度来卡:安全性、性能、兼容性。这三者就像是三足鼎立,缺一条腿就站不稳。
3.1 安全性——这条红线不能碰
安全性,说白了就是防破解的能力。这没什么商量的余地,一旦被破解,数据就裸奔了。
我评估一个算法的安全性,主要看三件事:
- 密钥长度:密钥越长,暴力破解的成本越高。目前 AES-128 已经足够安全,AES-256 是为未来 10 年准备的。
- 已知攻击向量:有没有已知的侧信道攻击?有没有被破解的前科?
- 后量子抵抗能力:这个可能听着有点远,但量子计算机来了之后,RSA 和 ECC 都会被秒杀。
我曾经在项目中接手过一个遗留系统,用了 DES 算法。你没看错,就是那个已经被 NIST 废弃了 20 年的 DES。原因是当初开发时“听说 DES 够用”。结果安全审计时,用 SSLyze 一测,直接被判定为高危漏洞。后来花了两个月才把整个系统全部迁移到 AES-256-GCM。
所以说,不要在生产环境使用已被淘汰的算法。这个亏,吃一次就够了。
选对称加密,AES 是第一选择。建议用 GCM 模式,自带认证标签,防篡改。非对称加密,RSA 选 2048 位以上,ECC 选 P-256 曲线。别再碰 RSA-1024 了,它已经不太安全。
3.2 性能——别让加密成为你的瓶颈
你想想看,一个后端 API 处理请求只需要 5ms,结果加密解密用了 10ms。这不是拖后腿吗?
性能不只看算法本身的快慢,还跟数据量和调用频率强相关。
我拿几个常用算法来做个对比(实际项目中测试数据):
| 算法 | 类型 | 密钥长度 | 加密 1KB 耗时 | 加密 1MB 耗时 | 推荐场景 |
|---|---|---|---|---|---|
| AES-256-GCM | 对称 | 256 bit | ~0.002 ms | ~1.8 ms | 请求体加密,TLS 内部 |
| ChaCha20-Poly1305 | 对称 | 256 bit | ~0.003 ms | ~2.1 ms | 移动端/IoT,无硬件加速 |
| RSA-2048 | 非对称 | 2048 bit | ~0.8 ms(公钥加密) | 不可用 | 密钥交换/签名 |
| ECDSA P-256 | 非对称 | 256 bit | ~0.1 ms(签名) | 不可用 | JWT 签名, 签发 |
注意看,RSA 在加密大量数据时性能很差。所以实践中,我们通常用混合加密——非对称加密只用来交换对称密钥,数据本体靠对称加密来处理。你想想看,如果直接拿 RSA 去加密几 MB 的请求体,那个接口基本就废了。
如果后端是 x86 服务器,有 AES-NI 指令集加速,选 AES-256-GCM。如果做移动端或 IoT,CPU 可能没有硬件加密指令,选 ChaCha20-Poly1305。按我的经验,大多数场景下这两种就足够了,别自我发明什么复杂算法,算法越简单越安全。
3.3 兼容性——别让一把锁锁死所有门
这一点很多人会忽略,但我吃过太多亏了。
兼容性,其实就是你选的算法能不能被多方正常使用。
举个例子:你后端用 Go 选了一个不太常见的算法实现,结果前端用 JavaScript 根本找不到现成的库,得自己手写。手写容易出 bug,出 bug 就解密不回来。这不是坑自己吗?
我梳理了一下,兼容性主要看这几个方面:
- 标准合规性:是不是 NIST / IETF 推荐的标准算法?FIPS 140-2 / 140-3 认证过没有?
- 生态广度:Java、Go、Python、Node.js、C++ 这些主流语言有没有成熟的实现库?
- 跨平台能力:在大端序和小端序机器上表现一致吗?Big-endian / Little-endian 的处理会不会引起兼容性问题?
- 版本演进:有没有旧的实现被废弃的风险?会不会因为安全更新导致你的代码无法运行?
- 优先选 AES、ChaCha20、RSA、ECDSA 这些「老牌正统」算法
- 实现时确认好模式和补齐方式(ECB 不要用!CBC/PKCS7 还行)
- 非对称加密如果涉及裸签名,Serialization 格式一定要统一(DER 还是 PEM 还是 Base64)
- 我曾经在一个跨语言项目里,对方用 Python 的 `PyCrypto` 加密,我用 Java 的 `Bouncy Castle` 解密,结果因为 padding 策略不一致,折腾了三天才找出来。所以一定要在契约文档里把 Padding 方式写死。
3.4 三权平衡:具体怎么选?
上面三条原则都说了,但现实很骨感——你经常要做出取舍。
我把它总结为一张对照表,你可以直接参考:
| 业务场景 | 安全优先级 | 性能优先级 | 兼容优先级 | 推荐方案 |
|---|---|---|---|---|
| 金融/政务接口 | 最高 | 中 | 高 | AES-256-GCM + ECDSA P-384 |
| 互联网开放 API | 高 | 高 | 最高 | AES-256-GCM(或 ChaCha20)+ ECDSA P-256 |
| IoT / 嵌入式设备 | 中 | 最高 | 中 | ChaCha20-Poly1305 + Ed25519 |
| 移动端(Android/iOS) | 高 | 高 | 高 | ChaCha20-Poly1305(无硬件加速时) |
| 内部微服务间通讯 | 中 | 中 | 中 | 直接用 TLS 1.3,不做应用层加密 |
我曾经看到有人为了实现「安全」,在 API 的每个请求里既用了非对称加密又套了对称加密,还在头上加了个自定义混淆层。性能直接掉了一个数量级,最后被运维强行下线。所以别为了安全感而过度设计,不恰当的过度加密比不加密更危险(因为没人会去维护它)。
3.5 小结:选型的终极心法
说了这么多,其实核心就一句话:
能用标准算法,就别选非标准;能用广泛支持的,就别选小众的;能用经过时间检验的,就别当小白鼠。
下面是代码层面的一个简单示例,演示在 Python 中如何做加密实际耗时测试:
import time
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
from cryptography.hazmat.backends import default_backend
def benchmark_aes_gcm(data_size=1024):
"""测试 AES-256-GCM 的加密性能"""
key = b'x' * 32
iv = b'x' * 12
aad = b''
plaintext = b'a' * data_size
start = time.perf_counter()
encryptor = Cipher(algorithms.AES(key), modes.GCM(iv), backend=default_backend()).encryptor()
encryptor.authenticate_additional_data(aad)
ciphertext = encryptor.update(plaintext) + encryptor.finalize()
end = time.perf_counter()
print(f"AES-256-GCM 加密 {data_size} 字节数据耗时: {end - start:.6f} 秒")
if __name__ == "__main__":
benchmark_aes_gcm(1024)
benchmark_aes_gcm(1048576) # 1 MB
输出结果基本能对上表里列出的数据。实际项目中,你最好拿自己真实业务数据量去跑一遍,别偷懒。
嗯,加密算法选型这件事,说难不难,说简单也不简单。记住三角框架,拿你的业务场景去套,基本上不会跑偏。