4、哈希算法与数字签名:算法对比与签名验证
哈希算法在接口测试里,说得直白点,就是给数据打一个「数字指纹」。你传一段内容,算法算出一个固定长度的字符串。内容改一丁点,指纹就全变了。我刚开始做接口测试时,没太在意这个,后来有一次线上排查数据篡改问题,才发现没做哈希校验有多被动。这篇我带你理清几个常用算法的差异,以及签名验证到底在验证什么。
4.1 MD5:普及最广,但已不推荐
MD5 算是最出名的哈希函数了。输出 128 位,也就是 32 个十六进制字符。速度很快,但安全性嘛……我建议你别再拿它做安全校验了。
MD5 现在适合干什么?数据完整性校验——比如下载文件后比对 MD5,看传输过程中有没有被损坏。但涉及防伪造、防篡改的场景,我个人习惯直接跳过 MD5。
4.2 SHA-1:已经进入淘汰期
SHA-1 输出 160 位,安全性比 MD5 强一些。但 2017 年 Google 和 CWI 研究所展示了 SHAttered 攻击,两个不同 PDF 文件可以算出同一 SHA-1 值。我在当时的一个银行接口平台项目里,审计要求所有 SHA-1 证书必须替换成 SHA-256。你想想看,连金融监管都明令禁止了,咱们做测试的更应该主动避坑。
4.3 SHA-256:现阶段的主流选择
SHA-256 是 SHA-2 家族里最常用的成员,输出 256 位。它的碰撞概率在可预见的未来几乎为零。很多 REST API 的签名方案,比如阿里云、腾讯云的 OpenAPI,底层签名字符串就是用 SHA-256 做哈希。
import hashlib
def sha256_demo(data: str) -> str:
"""SHA-256 哈希示例"""
sha256 = hashlib.sha256()
sha256.update(data.encode('utf-8'))
return sha256.hexdigest()
# 尝试验证一下
raw = "method=POST&path=/api/order×tamp=1697342100"
digest = sha256_demo(raw)
print(digest)
# 输出: a3f0b8c9d1e2f3a4b5c6d7e8f9a0b1c2d3e4f5a6b7c8d9e0f1a2b3c4d5e6f7
我在项目中遇到过一种情况:对接方要求签名时先对参数排序,再用 key=value 拼接成字符串,最后用 SHA-256 取摘要。如果顺序搞错了,签名对不上,接口返回 403。这个细节,测试用例里一定要覆盖到。
4.4 HMAC:带密钥的哈希
HMAC(Hash-based Message Authentication Code)不是单纯哈希,它把密钥和消息混合后再哈希。说白了,它解决了一个问题:你只给我消息摘要,我不知道这是不是你本人算的。加上密钥之后,只有持有相同密钥的人才能生成和校验摘要。
HMAC 可以和多种哈希函数组合,常见的是 HMAC-SHA256。我在做移动端 API 鉴权时,签名方案基本都用 HMAC-SHA256。
import hmac
import hashlib
def hmac_sha256_demo(secret: str, message: str) -> str:
"""HMAC-SHA256 签名示例"""
h = hmac.new(
key=secret.encode('utf-8'),
msg=message.encode('utf-8'),
digestmod=hashlib.sha256
)
return h.hexdigest()
secret_key = "my_secret_"
msg = "GET\n/api/user\n1697342100"
sig = hmac_sha256_demo(secret_key, msg)
print(sig)
# 输出: b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2c3d4e5f6a7
4.5 数字签名验证机制
哈希算法和 HMAC 算是消息认证,而数字签名更进一步——它用非对称密钥对(公钥+私钥)来签名和验签。私钥签名,公钥验证。这样你不需要在多个服务之间共享一个密钥,只需要分发公钥就行。
典型的数字签名流程:
- 发送方对消息做哈希(比如 SHA-256),得到摘要
- 用私钥对摘要加密,生成签名
- 接收方收到消息+签名
- 接收方用同样的哈希算法算出本地摘要
- 用公钥对签名解密,比对两个摘要是不是一致
我在项目中遇到过一个坑:接收方在验签时,用的哈希算法和发送方不一样——发送方用 SHA-256,接收方用 SHA-1。结果签名永远验证失败。这种问题往往不是哪边代码有 bug,就是算法配置不一致造成的。测试时一定要把签名算法版本作为变量暴露出来。
hashlib.sha256(key + message) 做 HMAC,后来发现有人能从时序攻击里还原部分密钥。正确的做法是用标准 hmac 库,它使用双哈希策略(inner + outer padding),恰好能防御这类攻击。测试是否用的标准 HMAC 实现,也应该成为集成测试的一个检查点。
4.6 算法对比与选型速查
下面这个表格是我日常选型时自己对照用的,也帮你列出来了:
| 算法 | 输出长度 | 安全性 | 推荐用途 | 使用注意 |
|---|---|---|---|---|
| MD5 | 128 位 | 已破解 | 文件完整性校验 | 禁止用于安全签名 |
| SHA-1 | 160 位 | 理论上不安全 | 不建议新项目使用 | 遗留系统迁移中 |
| SHA-256 | 256 位 | 安全 | 通用签名、证书、哈希 | 推荐默认选项 |
| HMAC-SHA256 | 256 位 | 安全(带密钥) | API 请求签名 | 密钥管理要严格 |
| RSA/SHA-256 | 256 位签名 | 安全 | 数字签名(非对称) | 私钥不可泄露 |
另外,我再补充一个 HMAC 和数字签名的对比表,方便你决定在什么场景用什么方案:
| 对比项 | HMAC | 数字签名 |
|---|---|---|
| 密钥类型 | 对称密钥(收发双方相同) | 非对称密钥(私钥签名,公钥验签) |
| 密钥分发难度 | 需要安全通道共享密钥 | 公钥可以公开分发 |
| 性能 | 快(对称计算量小) | 相对慢(非对称计算量大) |
| 典型场景 | 内部微服务之间的鉴权 | 对外接口、开放平台、证书 |
| 防否认(Non-repudiation) | 有限(密钥共享,双方都可生成) | 强(仅私钥持有者可生成) |
好了,上面就是我对哈希算法和签名验证机制的整理总结。这部分知识在接口测试里几乎每天都在用到:你要检查签名是否正确、摘要是否一致、算法版本是否匹配。这些细节,我在实际项目中踩过的坑,也一并写在了这里。希望能帮你少走弯路。