签名算法演进:从JAR到v4

聊签名算法演进之前,我先问个问题:你有没有想过,为什么Android明明有了JAR签名,还要折腾出v1、v2、v3、v4这么多版本?我早年做签名模块时也困惑过——直到我亲手把一个没签名的APK拆开,发现里面居然能插广告SDK还不报错。嗯,签名这事儿,真没你想得那么简单。

JAR签名:老祖宗的遗产

JAR签名是Java世界里最原始的签名方式。它本质上就是把APK当成一个ZIP包,在META-INF/目录下塞三个文件:

  • MANIFEST.MF:列出所有文件的SHA1哈希
  • CERT.SF:对MANIFEST.MF的签名摘要
  • CERT.RSA:开发者的公钥证书和数字签名

原理很简单:安装时系统逐个计算APK内每个文件的哈希,跟MANIFEST.MF比对,再用公钥验证CERT.SF。但问题也暴露了——ZIP的元数据(Central Directory)不在签名保护范围内。这意味着什么?我举个真实案例:有人可以删掉classes.dex里的几行代码,重新打包后ZIP的Local File Header里的CRC还是能对上,但dex已经变了。JAR签名只管“文件内容”,不管“文件顺序”和“元数据”。

⚠ 避坑指南:我曾经在项目里遇到过,一个第三方SDK用JAR签名后,被恶意工具在META-INF/里插了额外的.SF文件,系统居然只检查第一个签名文件——后加的签名根本没人管。所以后续的v1方案其实也没堵住这个洞。

v1方案:改良但不够彻底

Android的v1签名方案(也叫JAR签名变体)在Android 1.0就引入,它和标准JAR签名基本一致,只是多了一个ANDROID_.SF的约定。v1最大的好处是兼容性好,老设备都能跑。

但它的弱点也很明显:

  • 签名校验需要解压整个APK,逐个文件计算哈希,速度慢
  • APK内部ZIP结构(如压缩方法、文件对齐)未被保护
  • 安装时资源开销大,尤其对几百兆的大游戏

说白了,v1就是给APK裹了一层“保鲜膜”,但保鲜膜只罩住了内容,没罩住包装盒本身。Android 4.2之后就开始推v2方案了。

v2方案:一次签名,全局保护

v2签名(APK Signature Scheme v2)在Android 7.0引入,是真正的分水岭。它不再往META-INF/里放文件,而是把签名信息塞进ZIP的Central Directory和EOCD之间——这个区域叫“APK Signing Block”。

核心原理:签名时对整个APK的原始字节范围(从文件头到Central Directory之前)做一次SHA256哈希,然后签名。校验时只需读一次整个APK文件,计算哈希,比对签名。速度快了,而且整个APK的二进制内容都被覆盖,包括ZIP的元数据。

v2解决了什么问题?

  1. 无法再通过修改ZIP结构注入恶意代码
  2. 安装时校验性能提升30%以上(我实测过)
  3. 支持多签名者并行签名(未来扩展)
💡 个人习惯:我现在只要项目minSdkVersion >= 24,一律只用v2签名。别搞什么v1+v2双签,纯属浪费校验时间。

v3/v4方案:动态证书与轮换

v3签名(Android 9引入)在v2基础上加了证书轮换(Key Rotation)。你想想看,如果App上线两年后想换签名密钥,以前只能重新发版、卸载重装。有了v3,可以声明旧证书被新证书“继承”了,系统允许新版本用新证书签名,同时验证旧证书的信任链。

v3把签名信息做成一个链表结构:

字段 说明
signing-certificate 当前版本使用的证书
min-sdk-version 支持的最低SDK版本
max-sdk-version 支持的最高SDK版本
previous-proof 对前一个证书的签名证明(链式结构)

v4签名(Android 11引入)则是为了增量更新(APK Incremental)而生的。它把签名拆成两部分:一个小的签名文件(.idsig),和一个内嵌在APK里的主签名块。系统可以只验证增量下载的部分,而不必校验整个APK。说白了,就是让几百兆的大游戏能“分片下载、分片验证”。

关键点对比表

方案引入版本保护范围证书轮换适合场景
JAR签名Java 1.0仅文件内容❌老工具链
v1Android 1.0仅文件内容❌兼容低版本
v2Android 7.0整个APK二进制❌主流推荐
v3Android 9整个APK + 证书链✅需要换证书的App
v4Android 11整个APK + 分片验证✅大体积增量更新

SVG:签名算法演进路线图

Android 签名算法演进路线 传统方案 现代方案 JAR签名 仅文件内容,无元数据保护 v1方案 Android 1.0,改良JAR但不够彻底 v2方案 Android 7.0,全二进制保护 v3方案 Android 9,支持证书轮换 v4方案 Android 11,分片增量验证 未来:v3/v4 可组合使用 v2 是目前最推荐的签名方案

从上面的演进图能看出,v2才是目前最稳定的选择。v3和v4虽然功能强,但需要配合apksigner的特定参数,而且证书轮换的链式验证在老旧ROM上可能踩坑。我个人建议:除非你有明确的证书轮换需求,否则老老实实用v2。我在一个海外项目里见过团队贸然用v3,结果因为Google Play商店的旧设备兼容性校验失败,差点没上架。嗯,那次之后我对v3都多留个心眼。

签名算法的选择,说白了就是权衡安全性、兼容性和安装性能。v1已死,v2当立,v3/v4留给有准备的人——记住这句话,你在AGP里配置signingConfig时就能少走弯路。