攻击面分析:中间人攻击、重放攻击、签名绕过攻击、降级攻击

好,咱们进入第二章。上一章我们把签名更新的整体流程捋了一遍,现在该聊聊「敌人从哪来」了。

我常说一句话:不知道攻击面,就谈不上防御。你想想看,连对手可能从哪个方向出拳都不知道,你摆的防御姿势再好看也是白搭。

签名更新这个环节,说白了就是一条数据链路:从服务端生成签名,到客户端下载、校验、应用。这条链路上,有四个经典的攻击点。我这些年做安全评估,几乎每个项目都能碰到其中一两个。

核心观点:签名更新的攻击面,本质上是「信任链」上的每一个跳转点。只要有一个环节的信任被打破,整个更新机制就可能沦陷。

2.1 中间人攻击(MITM)

这是最直观的攻击方式。攻击者把自己插在客户端和服务端之间,拦截、篡改通信内容。

我记得有一次帮一家 IoT 厂商做审计,他们的设备固件更新走的是 HTTP。我当时就问:「你们不怕中间人吗?」对方答:「我们的签名很安全。」嗯,签名确实安全,但问题是——签名本身也是通过 HTTP 传输的。攻击者直接把整个响应包换掉,连签名带固件一起换,客户端拿什么去验证?

中间人攻击的常见场景:

  • 公共 Wi-Fi 劫持:攻击者在咖啡厅、机场架设恶意热点
  • DNS 欺骗:把更新服务器的域名解析到攻击者控制的 IP
  • 代理劫持:企业内网或运营商层面的透明代理
  • ARP 欺骗:局域网内伪造网关

防御中间人攻击,最直接的手段就是 TLS(HTTPS)。但这里有个坑——光用 HTTPS 还不够。我见过不少应用,HTTPS 是用了,但证书校验是关闭的,或者允许用户点击「继续」跳过警告。这跟没穿衣服有什么区别?

⚠️ 重要提醒:HTTPS 的证书校验必须做完整。包括:证书链验证、域名匹配、有效期检查、吊销状态查询。缺任何一项,中间人攻击都能绕过去。

2.2 重放攻击(Replay Attack)

重放攻击,说白了就是「录下来,再放一遍」。攻击者不需要破解你的签名,也不需要篡改数据,只需要把之前一次合法的更新请求原封不动地再发一次。

什么时候重放攻击会生效?当你的更新包是「一次有效、长期有效」的时候。

我举个真实例子。某款车载娱乐系统,它的签名更新包没有时间戳。攻击者抓包拿到一次合法的地图更新包,然后等厂商发布了新版本、修复了旧漏洞之后,攻击者把那个旧包重放给还没升级的车机。车机一看:签名正确,版本号比当前高?好,更新!结果呢?车机被「降级」到了有漏洞的旧版本。

重放攻击的防御要点:

  • 加入时间戳:签名时嵌入当前时间,客户端校验时检查时间窗口
  • 使用 nonce(一次性随机数):服务端记录已使用的 nonce,拒绝重复
  • 版本号递增校验:客户端记录当前版本,拒绝低于或等于当前版本的更新包
💡 实战技巧:我个人习惯把时间戳和 nonce 一起用。时间戳防止大范围重放,nonce 防止短时间内的精确重放。两者配合,基本能堵死重放攻击。

2.3 签名绕过攻击(Signature Bypass)

这个攻击面,是四个里面技术含量最高的,也是我最喜欢研究的方向。签名绕过,不是去破解密码学算法,而是让签名校验逻辑「失效」。

常见的绕过方式有哪些?我列一下:

攻击方式 原理 典型案例
校验逻辑跳过 通过逆向修改客户端代码,跳过签名校验函数 Hook 掉 verifySignature() 直接返回 true
公钥替换 替换客户端内置的公钥,用自己的私钥签名 修改 APK 中的公钥证书文件
校验路径截断 利用路径遍历或符号链接,让校验器读到错误文件 在校验前用符号链接替换更新包
类型混淆 利用不同数据类型的解析差异绕过校验 签名格式是 JSON,但解析器有 bug
回滚到未签名版本 利用降级逻辑,让客户端接受不带签名的旧包 版本号比较逻辑存在整数溢出

我曾经在一个嵌入式设备上遇到过「公钥硬编码在二进制里,但攻击者可以直接用十六进制编辑器替换」的情况。你说这算不算签名绕过?算,而且是最简单粗暴的那种。

防御签名绕过,核心原则就一条:签名校验必须完整、不可跳过、不可篡改。具体做法包括:

  • 校验逻辑放在安全执行环境(TEE/SE)中
  • 公钥存储在防篡改区域(如 eFuse)
  • 对客户端代码进行完整性校验(代码签名)
  • 使用混淆和反调试技术增加逆向难度

2.4 降级攻击(Downgrade Attack)

降级攻击,名字听着温和,实际上非常致命。攻击者不直接攻击你的签名,而是诱导客户端接受一个旧版本——这个旧版本里有已知漏洞,攻击者再利用那个漏洞完成后续攻击。

降级攻击的典型流程:

  1. 攻击者拦截更新服务器的响应
  2. 将响应中的版本号改为一个旧版本(如 1.0.0)
  3. 客户端校验签名通过(旧版本也有合法签名)
  4. 客户端降级到有漏洞的 1.0.0 版本
  5. 攻击者利用 1.0.0 的漏洞完成提权或数据窃取

你可能会问:「旧版本的签名也是合法的,客户端凭什么拒绝?」问得好。这就是降级攻击最难防的地方——签名本身没错,错的是版本管理策略。

防御降级攻击,我总结了几个要点:

  • 版本号单调递增:客户端只允许升级,不允许降级
  • 签名中包含版本号:确保签名和版本号绑定,不能拆开复用
  • 最小可接受版本:服务端下发一个「最低允许版本」,低于此版本的更新包直接拒绝
  • 关键安全补丁不可降级:对于修复了高危漏洞的版本,标记为「不可降级」
⚠️ 特别注意:降级攻击经常和重放攻击配合使用。攻击者先重放一个旧版本的合法更新包,然后利用旧版本的漏洞绕过签名校验。两个攻击面叠加,威力翻倍。

2.5 攻击面全景图

说了这么多,咱们用一张图把四个攻击面的关系理清楚。

签名更新攻击面全景图 签名更新攻击面全景图 签名更新流程 中间人攻击 重放攻击 签名绕过攻击 降级攻击 拦截/篡改通信 HTTPS 证书校验缺失 公共 Wi-Fi / DNS 欺骗 重放旧版本更新包 缺少时间戳 / nonce 版本号未递增校验 绕过签名校验逻辑 Hook / 公钥替换 校验路径截断 诱导客户端接受旧版本 版本号未绑定签名 缺少最小版本限制 防御核心:信任链的每一环都必须独立验证 传输层 + 签名层 + 版本层 + 执行层,四层防御缺一不可 配合 配合 降级依赖

从这张图你能看出来,四个攻击面不是孤立的。中间人攻击可以为重放攻击创造条件,重放攻击可以配合降级攻击使用,降级攻击又可能绕过签名校验。攻击者往往不会只用一招,而是组合拳。

所以,防御也必须体系化。你不能只防中间人不管降级,也不能只加固签名校验忽略重放。我个人的经验是:把签名更新看作一个完整的信任链,每个环节都做独立校验。传输层用 TLS,签名层用强密码学,版本层做单调递增,执行层做完整性校验。四层都守住,攻击者才真的无从下手。