请点赞关注,你的支持对我意义重大。
🔥 Hi,我是小彭。本文已收录到 GitHub · AndroidFamily 中。这里有 Android 进阶成长知识体系,有志同道合的朋友,关注公众号 [彭旭锐] 带你建立核心竞争力。
前言
- 在打生产包时,一定需要对 apk 签名,那么你知道为什么要给应用签名吗?
- 在这篇文章里,我将分析 Android apk 的签名机制,并介绍 v1、v2 和 v3 三种安装包签名方案的原理与演进。如果能帮上忙,请务必点赞加关注,这真的对我非常重要。
这篇文章是 Gradle 系列文章第 10 篇,相关 Android 工程化专栏完整文章列表:
一、Gradle 基础:
- 1、Gradle 基础 :Wrapper、Groovy、生命周期、Project、Task、增量
- 2、Gradle 插件:Plugin、Extension 扩展、NamedDomainObjectContainer、调试
- 3、Gradle 依赖管理
- 4、Maven 发布:SHAPSHOT 快照、uploadArchives、Nexus、AAR
- 5、Gradle 插件案例:EasyPrivacy、so 文件适配 64 位架构、ABI
二、AGP 插件:
- 1、AGP 构建过程
- 2、AGP 常用配置项:Manifest、BuildConfig、buildTypes、壳工程、环境切换
- 3、APG Transform:AOP、TransformTask、增量、字节码、Dex
- 4、AGP 代码混淆:ProGuard、R8、Optimize、Keep、组件化
- 5、APK 签名:认证、完整性、v1、v2、v3、Zip、Wallet
- 6、AGP 案例:多渠道打包
三、组件化开发:
- 1、方案积累:有赞、蘑菇街、得到、携程、支付宝、手淘、爱奇艺、微信、美团
- 2、组件化架构基础
- 3、ARouter 源码分析
- 4、组件化案例:通用方案
- 5、组件化案例:组件化事件总线框架
- 6、组件化案例:组件化 Key-Value 框架
四、AOP 面向切面编程:
- 1、AOP 基础
- 2、Java 注解
- 3、Java 注解处理器:APT、javac
- 4、Java 动态代理:代理模式、Proxy、字节码
- 5、Java ServiceLoader:服务发现、SPI、META-INF
- 6、AspectJ 框架:Transform
- 7、Javassist 框架
- 8、ASM 框架
- 9、AspectJ 案例:限制按钮点击抖动
五、相关计算机基础
目录
前置知识
这篇文章的内容会涉及以下前置 / 相关知识,贴心的我都帮你准备好了,请享用~
1. 什么是应用签名?
1.1 数字签名模型
数字签名(Digital Signature)也叫作数字指纹(Digital Fingerprint),它是消息摘要算法和非对称加密算法的结合体,能够验证数据的完整性,并且认证数据的来源。
数据签名算法的模型分为两个主要阶段:
- 1、签名: 先计算数据的 [摘要],再使用私钥对 [摘要] 进行加密生成 [签名],将 [数据 + 签名] 一并发送给接收方;
- 2、验证: 先使用相同的摘要算法计算接收数据的 [摘要],再使用预先得到的公钥解密 [签名],对比 [解密的签名] 和 [计算的摘要] 是否一致。若一致,则说明数据没有被篡改。
需要注意的是,Android 目前不对应用证书进行 CA 认证,应用可以由第三方(OEM、运营商、其他应用市场)签名,也可以自行签名。
1.2 为什么要给应用签名?
应用 APK 其实是一种特殊的 Zip 压缩包,无法避免恶意激活成功教程者解压 / 反编译修改内容,针对这个问题有何解决方案呢?他山之石,可以攻玉 ——数字签名算法。应用签名正是数字签名算法的应用场景之一,与其他应用场景类似,目的无非是:
- 认证
Android 平台上运行的每个应用都必须有开发者的签名。在安装应用时,软件包管理器会验证 APK 是否已经过适当签名,安装程序会拒绝没有获得签名就尝试安装的应用。
- 验证完整性
软件包管理器在安装应用前会验证应用摘要,如果激活成功教程者修改了 apk 里的内容,那么摘要就不再匹配,验证失败(验证流程见下文方案)。
提示: 使用数字签名的优点是验证过程无须复杂的接口和权限,只需要在本机验证。
1.3 应用签名方案演进
截止至 Android 11,Android 支持以下三种应用签名方案:
- v1 签名方案:基于 Jar 签名;
- v2 签名方案:提高验证速度和覆盖度(在 Android 7.0 Nougat 中引入);
- v3 签名方案:实现密钥轮转(在 Android 9.0 Pie 中引入)。
为了提高兼容性,必须按照 v1、v2、v3 的先后顺序采用签名方案,低版本平台会忽略高版本的签名方案在 APK 中添加的额外数据。
引用自 source.android.com/security/ap… —— Android Developers
2. 签名方案 v1
v1 签名方案是基于 Jar 的签名。
2.1 签名产物
首先,我们先来分析其签名产物。v1 签名后会增加 META-INF 文件夹,其中会有如下三个文件。考虑到使用不同的证书和签名方式,得到的文件名可能不同,因此你只要留意文件的后缀即可:
META-INF
├── MANIFEST.MF
├── CERT.SF
├── CERT.RSA
文件 | 描述 |
---|---|
MANIFEST.MF | 记录「apk 中每一个文件对应的摘要」(除了 META-INF 文件夹) |
*.SF | 记录「MANIFEST.MF 文件的摘要」和「MANIFEST.MF 中每个数据块的摘要」 |
*.RSA | 包含了「*.SF 文件的签名」和「包含公钥的开发者证书」 |
提示: 如果 apk 中文件数很多,而且文件名很长,那么 MANIFEST.MF 和 *.SF 两个文件会变得很大。有没有办法优化呢?见 第 5.1 节 优化摘要记录文件大小。
2.2 签名流程
v1 签名流程如下:
- 1、计算每个文件的 SHA-1 摘要,进行 BASE64 编码后写入 MANIFEST.MF 文件;
MANIFEST.MF(Message Digest File,摘要文件)
Manifest-Version: 1.0
Built-By: Generated-by-ADT
Created-By: Android Gradle 3.1.0
Name: AndroidManifest.xml
SHA1-Digest: 9hTSmRfzHEeQc7V2wxBbTT3DmCY= 【文件的摘要】
...
- 2、计算整个 MANIFEST.MF 文件的 SHA-1 摘要,进行 BASE64 编码后写入 *.SF 文件;
- 3、计算 MANIFEST.MF 文件中每一块摘要的 SHA-1 摘要,进行 BASE64 编码后写入 *.SF 文件;
\*.SF(Signature File,签名文件)
Signature-Version: 1.0
Created-By: 1.0 (Android)
SHA1-Digest-Manifest: MJQyZ0dc4dv7G9nlJPAMQLwEwbU= 【MANIFEST.MF 文件的摘要】
X-Android-APK-Signed: 2
Name: AndroidManifest.xml
SHA1-Digest: IJioMmfD693T4qnUJcPKhq9woHQ= 【摘要的摘要】
...
- 4、计算整个 *.SF 文件的数字签名(先摘要再私钥加密);
- 5、将数字签名和 X.509 开发者数字证书(公钥)写入 *.RSA 文件。
提示:*.RSA 文件加密了,需要使用 openssl 工具打开。
引用自 zhuanlan.zhihu.com/p/108034286 —— 木质的旋律 著
2.3 验证流程
验证流程可以分为验证签名和验证完整性两个步骤:
验证签名步骤:
- 1、取出 *.RSA 中包含的开发者证书;
- 2、【注意:这里不向 CA 认证开发者证书合法性】;
- 3、用证书中的公钥解密 *.RSA 中包含的签名,得到摘要;
- 4、计算 *.SF 的摘要;
- 5、对比 (3) 和 (4) 的摘要是否一致;
如果上述签名验证结果正确,才会验证完整性:
- 1、计算 MANIFEST.MF 的摘要;
- 2、对比 *.SF 记录中的文件摘要和 (1) 的摘要是否一致;
- 3、如果一致,再用 MANIFEST.MF 中的每一块数据去校验每一个文件是否被修改。
以上任何步骤验证失败,则整个 APK 验证失败。
2.4 存在的问题
- 完整性覆盖范围不足:Zip 文件中部分内容不在验证范围,例如 META-INF 文件夹;
- 验证速度较差:验证程序必须解压所有压缩的条目,这需要花费更多时间和内存。
为了解决这些问题,Android 7.0 中引入了 APK 签名方案 v2。
3. 签名方案 v2
v2 签名方案是一种 全文件签名方案,该方案能够发现对 APK 的受保护部分进行的所有更改,相对于 v1 签名方案验证速度更快,完整性覆盖范围更广。
提示: 为了兼容低版本,使用 v2 签名方案的同时,还需要使用 v1 签名方案。
3.1 Zip 文件简介
在分析 v2 签名方案之前,我们先简单了解一下 Zip 文件格式:
-
Zip 文件主体结构分为三个部分:「条目内容区」&「中央目录区」&「中央目录结尾区(EoCD)」。
-
EoCD 中记录了中央目录的起始位置,在「条目内容区」和「中央目录区」之间插入了其他数据不会影响 Zip 解压。
3.2 签名产物
首先,我们先来分析其签名产物。v2 签名后会在 「条目内容区」和「中央目录区」之间插入「APK 签名分块(APK Signing Block)」。
引用自 source.android.com/security/ap… —— Android Developers
从左到右边,我们定义为区块 1~4。
3.2 签名流程
相对与 v1 签名方案,v2 签名方案不再以文件为单位计算摘要了,而是以 1 MB 为单位将文件拆分为多个连续的块(chunk),每个分区的最后一个块可能会小于 1 MB。
v2 签名流程如下:
- 1、对区块 1、3、4,按照 1MB 大小分割为多个块(chunk);
- 2、计算每个块的摘要;
- 3、计算 (2) 中所有摘要的签名。
- 4、添加 X.509 开发者数字证书(公钥)
引用自 source.android.com/security/ap… —— Android Developers
3.3 验证流程
验证流程可以分为验证签名和验证完整性两个步骤:
- 验证签名步骤:用公钥验证区块 2 的签名;
- 验证完整性步骤:用「APK数据摘要集」验证每一块数据的摘要。
4. 签名方案 v3
签名方案 v3 支持密钥轮换,应用能够在 APK 更新过程中更改其签名密钥。
【累了,后面先不写了…】
5. 衍生应用场景
这一节,我们介绍基于 Android 应用签名机制的衍生应用场景。
5.1 优化摘要记录文件大小
在 v1 方案中,MANIFEST.MF 和 *.SF 这两个文件会记录大量的文件名和文件摘要。如果 apk 中文件数很多,而且文件名很长,那么这两个文件会变得很大。使用 AndResGuard 工具,可以将文件名转换为短路径文件名,从而减少这两个文件的大小。
引用自 time.geekbang.org/column/arti… —— 张绍文 著
5.2 多渠道打包方案
在实际生产中,往往需要生成多个渠道的 APK 包,传统的方法是使用 APKTool 逆向工具、Flavor + BuildType 等方案,这一类多渠道打包方案的缺点是耗时严重。随着 Android 应用签名方案的演进,演变出了不同的多渠道打包方案:
v1 方案时代下的多渠道打包
- 添加空文件
在 v1 方案中,我们提到了完整性校验不覆盖到 META-INF 文件夹的问题。有些多渠道打包方案就是利用了这个问题,在 META-INF 文件夹下添加空文件,用空文件的名称来作为渠道的唯一标识,就可以节省打包的时间,提高打渠道包的速度。
- Zip Comment
除了添加空文件的方法,还可以向 APK 添加 Zip Comment 来生成多渠道包(APK 本身就是特殊的 Zip 包)。
v2 方案时代下的多渠道打包
在 v2 签名方案中,几乎整个 APK 都纳入保护范围,如果向 APK 添加空文件或 Zip Comment 的话,在安装时会报以下错误:
Failure [INSTALL_PARSE_FAILED_NO_CERTIFICATES:
Failed to collect certificates from base.apk: META-INF/CERT.SF indicates base.apk is signed using APK Signature Scheme v2,
but no such signature was found. Signature stripped?]
新背景下的多渠道打包方案,则是利用了 APK 签名分块(区块 2)不受保护 & 字段可扩展的特点,向区块中添加多渠道信息(ID-Value),例如 美团多渠道打包方案 Walle。
6. 总结
-
签名应用是处于两个目的:认证 & 验证完整性,即:认证 APK 的开发者以及验证 APK 内容是否被篡改。截止到 Android 11,一共有 v1、v2、v3 三种签名方案。
-
v1 是基于 Jar 的签名方案,它存在完整性覆盖范围不足 & 验证速度较差两个问题。
-
Android 7.0 推出的 v2 签名方案优化了这两个问题,通过「条目内容区」和「中央目录区」之间插入「APK 签名分块(APK Signing Block)」,优化了 v1 方案的两大问题。
-
Android 9.0 推出的 v3 方案是 v2 方案的优化版本,满足了密钥轮换的需求。
参考资料
- 《Signed_JAR_File》 —— Oracle
- 《应用签名》 —— Android Developers
- 《对应用进行签名》 —— Android Developers
- 《APK 签名方案 v2》 —— Android Developers
- 《APK 签名方案 v3》 —— Android Developers
- 《Android 应用安全防护和逆向分析》(第 12 章)—— 姜维 著
- 《Android 端 V1/V2/V3 签名的原理》 —— 木质的旋律 著(阿里巴巴技术团队)
- 《分析Android V2新签名打包机制》 —— pisazzpan 著(腾讯音乐技术团队)
- 《新一代开源Android渠道包生成工具Walle》 —— 建帅 陈潼 著(美团技术团队)
- 《Android V1及V2签名原理简析》 —— 看书的蜗牛 著(网易技术团队)
- 《Android App包瘦身优化实践》 —— 建帅 著(美团技术团队)
- 《Android 开发高手课 · 包体积优化(下)》 —— 张绍文 著(微信技术团队),极客时间 出品
- 《深入理解 Android 内核设计思想》(第 20 章) —— 林学森 著
我是小彭,带你构建 Android 知识体系。技术和职场问题,请关注公众号 [彭旭锐] 私信我提问。
今天的文章Gradle(10)一篇文章看懂 v1/v2/v3 签名机制分享到此就结束了,感谢您的阅读。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/21930.html