3、常见失败原因总览

签名校验失败,说白了就是「验签没通过」。我排查过不下百次这类问题,发现翻来覆去就那么几个坑。今天我把它们全摆出来,你对照着看,能省不少时间。

核心结论:90% 的签名校验失败,都逃不出下面这五类原因。记住它们,排查时心里就有底了。

签名校验失败五大原因 签名校验失败 密钥不匹配 公钥/私钥对不上 数据被篡改 内容与签名不匹配 算法不一致 SHA256 vs SHA1 时间戳问题 时钟偏差/时区错误 证书过期 有效期已截止 排查建议 1. 先确认密钥是否匹配——这是最常见的问题 2. 再检查数据完整性——看有没有被中间人篡改 3. 最后核对算法和时间——细节决定成败

3.1 密钥不匹配

这是最常踩的坑,没有之一。签名用的是私钥,验签用的是公钥。这两把钥匙必须是一对,否则怎么验都是失败。

我记得有一次,同事折腾了一下午,最后发现他把测试环境的公钥配到了生产环境。你说冤不冤?

场景 典型表现 排查方向
公钥与私钥不配对 每次验签都失败,错误码固定 检查密钥对的生成时间、指纹
公钥配置错误 部分环境正常,部分失败 对比各环境的公钥文件
密钥格式不对 解析密钥时报错 确认 PEM/DER 格式是否匹配

我的习惯:每次部署前,我会用 openssl 命令验证一下公钥和私钥是否匹配。就一行命令的事,能省掉后面几小时的排查时间。

# 验证私钥和公钥是否匹配
openssl pkey -in private.pem -pubout | openssl md5
openssl x509 -in public.pem -pubkey | openssl md5
# 对比两个 MD5 值,一致就没问题

3.2 数据被篡改

签名校验的本质,就是验证「数据」和「签名」是否对应。如果有人改了数据内容,但没重新生成签名,那验签必然失败。

为什么会这样?你想想看,签名是对原始数据的哈希值做的加密。数据一变,哈希值就变了,用公钥解出来的哈希值对不上,自然就失败了。

  • 传输中被篡改:中间人攻击、代理服务器修改了请求体
  • 拼接顺序错误:签名时参数的顺序和验签时不一致
  • 编码问题:URL 编码、Base64 编码前后不一致

我曾经踩过的坑:有一次排查了半天,最后发现是客户端把参数做了 URL 解码,但服务端验签时用的是原始编码后的字符串。两边数据不一样,签名怎么可能通过?

3.3 算法不一致

签名算法有很多种:RSA、ECDSA、HMAC……每种又有不同的哈希算法搭配。签名方和验签方用的算法必须完全一致。

我见过最离谱的一次,服务端用的是 SHA256withRSA,客户端用的是 SHA1withRSA。两边都觉得自己没错,但就是验不过。

常见算法组合 签名方 验签方
RSA + SHA256 SHA256withRSA SHA256withRSA
ECDSA + SHA256 SHA256withECDSA SHA256withECDSA
HMAC-SHA256 HmacSHA256 HmacSHA256

关键点:算法名称的字符串也要完全一致。比如 Java 里的 "SHA256withRSA" 和 "SHA256WithRSA"(大小写不同),在某些库中会被认为是不同的算法。

3.4 时间戳问题

很多签名机制会加入时间戳,防止重放攻击。如果客户端和服务端的时间不一致,签名就会失效。

说白了,就是你的签名里带了一个「当前时间」,服务端收到后一看——这时间不对啊,要么是未来,要么是过去太久,直接拒掉。

  • 时钟偏差:服务器和客户端时间差超过允许范围(通常是 5 分钟)
  • 时区问题:一个用 UTC,一个用 GMT+8,差了好几个小时
  • 时间格式:时间戳是秒还是毫秒?这个搞错了也会出问题

我建议:所有服务统一使用 UTC 时间,时间戳用毫秒级。客户端和服务端都配置 NTP 自动同步,能省掉 90% 的时间相关问题。

3.5 证书过期

证书是有有效期的。过期了,签名校验自然就失败了。这个问题其实很好排查,但往往被忽略。

我记得有一次线上告警,查了半天,最后发现是证书刚好在凌晨 0 点过期。嗯,就是这么巧。

证书状态 验签结果 处理方式
有效期内 正常通过 无需处理
已过期 失败,返回证书过期错误 更新证书,重新部署
即将过期(30天内) 正常通过,但应预警 提前申请新证书,安排轮换

注意:证书过期不是瞬间切换的。旧证书过期后,新证书还没部署上去,中间会有个空窗期。我建议提前两周就开始准备证书轮换,别等到最后一刻。