Android 签名机制

官方文档:https://source.android.com/security/apksigning

一、为什么要给应用签名

避免外部恶意解压、破解或者反编译修改内容,其签名的本质是:

  • 认证:Android 平台上运行的每个应用都必须有开发者的签名。在安装应用时,软件包管理器会验证 APK 是否已经过适当签名,安装程序会拒绝没有获得签名就尝试安装的应用。
  • 验证完整性:软件包管理器在安装应用前会验证应用摘要,如果破解者修改了 apk 里的内容,那么摘要就不再匹配,验证失败(验证流程见下文方案)。

二、应用签名方案类型

截止至 Android 11,Android 支持以下三种应用签名方案:

  • v1 :基于 Jar 签名;
  • v2 :提高验证性能 & 覆盖范围(Android 7.0  Nougat 引入);
  • v3 :支持密钥轮换(Android 9.0 Pie 引入)。

为了提高兼容性,必须按照 v1、v2、v3 的先后顺序采用签名方案,低版本平台会忽略高版本的签名方案在 APK 中添加的额外数据,具体流程如下图:

Android 签名

签名方案:v1


1. 简介

最基本的签名方案,是基于Jar的签名。

2. 签名产物

v1 签名后会增加 META-INF 文件夹,其中会有如下三个文件:

文件描述
「MANIFEST.MF」记录「apk 中每一个文件对应的摘要」(除了 META-INF 文件夹)
「*.SF」记录「MANIFEST.MF 文件的摘要」和「MANIFEST.MF 中每个数据块的摘要」
「*.RSA」包含了「*.SF 文件的签名」和「包含公钥的开发者证书」

3. 签名流程

  1. 计算每个文件的 SHA-1 摘要,进行 BASE64 编码后写入摘要文件,即 MANIFEST.MF 文件;
  2. 计算整个 MANIFEST.MF 文件的 SHA-1 摘要,进行 BASE64 编码后写入签名文件,即*.SF 文件;
  3. 计算 MANIFEST.MF 文件中每一块摘要的 SHA-1 摘要,进行 BASE64 编码后写入 签名文件,即*.SF 文件;
  4. 计算整个 *.SF 文件的数字签名(先摘要再私钥加密);
  5. 将数字签名和 X.509 开发者数字证书(公钥)写入 *.RSA 文件。

4. 验证流程

分为验证签名、验证完整性两个步骤:

步骤1:验证签名步骤

  1. 取出 *.RSA 中包含的开发者证书;
  2. 【注意:这里不向 CA 认证开发者证书合法性】;
  3. 用证书中的公钥解密 *.RSA 中包含的签名,得到摘要
  4. 用证书中的公钥计算 *.SF 的摘要;
  5. 对比 (3) 和 (4) 的摘要是否一致;

如果上述签名验证结果正确,就会去验证完整性:

步骤2:验证完整性

  1. 计算 MANIFEST.MF 的摘要;
  2. 对比 *.SF 中的摘要和 (1) 的摘要是否一致;
  3. 如果一致,再用 MANIFEST.MF 中的每一块数据去校验每一个文件是否被修改。

以上任何步骤验证失败,则整个 APK 验证失败。

5. 存在的问题

  • 覆盖范围不足:Zip 文件中部分内容不在验证范围,例如 META-INF 文件夹;
  • 验证性能差:验证程序必须解压所有压缩的条目,这需要花费更多时间和内存。

为了解决这些问题,Android 7.0 中引入了 APK 签名方案 v2。

签名方案:v2

1. 简介

一种 「全文件签名方案」,该方案能够发现对 APK 的受保护部分进行的所有更改。

2. 特点

相对于 v1 签名方案验证速度更快,完整性覆盖范围更广。为了兼容低版本,使用 v2 签名方案的同时,还需要使用 v1 签名方案。

3. Zip文件简介

在分析 v2 签名方案之前,我们先简单了解一下 Zip 文件格式:

  • Zip 文件主体结构分为三个部分:条目内容区、中央目录区、中央目录结尾区。
  • EoCD 中记录了中央目录的起始位置,「在「条目内容区」和「中央目录区」之间插入了其他数据不会影响 Zip 解压。」

4. 签名产物

v2 签名后会在 条目内容区(Contents of ZIP entries) 和 中央目录区(Central Directory) 之间插入APK 签名分块(APK Signing Block),如下图所示。从左到右边,我们定义为区块 1~4。

5. 签名流程

相对与 v1 签名方案,v2 签名方案不再以文件为单位计算摘要了,而是以 1 MB 为单位将文件拆分为多个连续的块(chunk),每个分区的最后一个块可能会小于 1 MB。v2 签名流程如下:

  1. 对区块 1、3、4,按照 1MB 大小分割为多个块(chunk);
  2. 计算每个块的摘要;
  3. 计算 (2) 中所有摘要的签名。
  4. 添加 X.509 开发者数字证书(公钥)

6. 验证流程

分为验证签名、验证完整性两个步骤:

  1. 验证签名:用公钥验证区块 2 的签名;
  2. 验证完整性:用「APK数据摘要集」验证每一块数据的摘要。

签名方案:v3

1. 简介

Android 9.0 中引入了新的签名方式。

2. 特点

v3 签名在 v2 的基础上,仍然采用检查整个压缩包的校验方式。不同的是在签名部分可以添加新的证书(Attr块)。在这个新块中,会记录我们之前的签名信息以及新的签名信息,支持密钥轮换,即以密钥转轮的方案,来做签名的替换和升级。这意味着,只要旧签名证书在手,应用能够在 APK 更新过程中更改其签名密钥。

3. 签名产物

v3 签名新增的新块(attr)存储了所有的签名信息,由更小的 Level 块,以链表的形式存储。

4. 签名流程

Android 的签名方案的升级都需要确保向下兼容。因此,在引入 v3 方案后会根据 APK 签名方案,v3 -> v2 -> v1 依次尝试验证 APK。而较旧的平台会忽略 v3 签名并尝试 v2 签名,最后才去验证 v1 签名。整个验证的过程,如下图:

这需要特别注意的是:对于覆盖安装的情况,签名校验只支持升级而不支持降级。即一个使用 V1 签名的 Apk,可以使用 V2 签名的 Apk 进行覆盖安装,反之则不允许。

总结

  • 应用签名的作用:认证 & 验证完整性
  • Android 签名方案类型:v1、v2、v3
  • v1 签名方案:基于 Jar 的签名方案,但存在的问题:完整性覆盖范围不足 & 验证性能差
  • v2 签名方案:通过条目内容区、中央目录区之间插入APK 签名分块(APK Signing Block)对v1签名进行了优化
  • v3 签名方案:支持密钥轮换,新增的新块(attr)存储了所有的签名信息,对 v2 签名进行了优化。

发表评论

您的电子邮箱地址不会被公开。 必填项已用*标注