应用签名允许开发者识别应用的作者,并在无需创建复杂的接口和权限的情况下更新应用。在 Android 平台上运行的每个应用都必须经开发者签名。尝试在未签名的情况下安装的应用会被 Google Play 或 Android 设备上的软件包安装程序拒绝。
在 Google Play 上,应用签名在 Google 与开发者之间以及开发者与其应用之间架起了信任的桥梁。开发者知道他们的应用以未修改的形式提供给 Android 设备;并且开发者可以对其应用的行为了解负责。
在 Android 上,应用签名是将应用置于其应用沙盒中的第一步。签名的应用证书定义了哪个用户 ID 与哪个应用相关联;不同的应用在不同的用户 ID 下运行。应用签名确保一个应用无法访问任何其他应用,除非通过明确定义的 IPC。
当应用(APK 文件)安装到 Android 设备上时,软件包管理器会验证 APK 是否已使用该 APK 中包含的证书正确签名。如果证书(或者更准确地说,证书中的公钥)与用于对设备上任何其他 APK 进行签名的密钥匹配,则新的 APK 可以在清单中指定它与另一个类似签名的 APK 共享 UID。
应用可以由第三方(OEM、运营商、替代市场)签名或自签名。Android 提供使用自签名证书的代码签名,开发者无需外部协助或权限即可生成这些证书。应用不必由中央机构签名。Android 目前不对应用证书执行 CA 验证。
应用还可以声明签名保护级别的安全权限,从而仅限制对使用相同密钥签名的应用的访问,同时保持不同的 UID 和应用沙盒。使用共享 UID 功能可以实现与共享应用沙盒更紧密的关系,其中两个或多个使用相同开发者密钥签名的应用可以在其清单中声明共享 UID。
APK 签名方案
Android 支持三种应用签名方案
- v1 方案:基于 JAR 签名
- v2 方案:APK 签名方案 v2,于 Android 7.0 中引入。
- v3 方案:APK 签名方案 v3,于 Android 9 中引入。
为了获得最佳兼容性,请使用所有方案对应用进行签名,先使用 v1,再使用 v2,然后使用 v3。Android 7.0 及更高版本的设备安装使用 v2+ 方案签名的应用比仅使用 v1 方案签名的应用更快。旧版 Android 平台会忽略 v2+ 签名,因此需要应用包含 v1 签名。
JAR 签名(v1 方案)
APK 签名从一开始就是 Android 的一部分。它基于已签名 JAR。如需详细了解如何使用此方案,请参阅 Android Studio 文档中的为您的应用签名。
v1 签名不保护 APK 的某些部分,例如 ZIP 元数据。APK 验证程序需要处理大量不受信任(尚未验证)的数据结构,然后丢弃签名未涵盖的数据。这提供了相当大的攻击面。此外,APK 验证程序必须解压缩所有压缩条目,从而消耗更多时间和内存。为了解决这些问题,Android 7.0 引入了 APK 签名方案 v2。
APK 签名方案 v2 和 v3(v2+ 方案)
运行 Android 7.0 及更高版本的设备支持 APK 签名方案 v2(v2 方案)及更高版本。(v2 方案在 Android 9 中更新为 v3,以在签名块中包含其他信息,但其他方面的工作方式相同。)APK 的内容经过哈希处理和签名,然后将生成的 APK 签名块插入到 APK 中。如需详细了解如何将 v2+ 方案应用于应用,请参阅APK 签名方案 v2。
在验证期间,v2+ 方案将 APK 文件视为 Blob,并对整个文件执行签名检查。对 APK 的任何修改(包括 ZIP 元数据修改)都会使 APK 签名失效。这种形式的 APK 验证速度明显更快,并且能够检测到更多类别的未经授权的修改。
新格式向后兼容,因此使用新签名格式签名的 APK 可以安装在旧版 Android 设备上(这些设备只是忽略添加到 APK 的额外数据),前提是这些 APK 也已使用 v1 签名。
图 1. APK 签名验证流程
APK 的整个文件哈希值根据 APK 签名块中存储的 v2+ 签名进行验证。哈希值涵盖除 APK 签名块之外的所有内容,APK 签名块包含 v2+ 签名。对 APK 签名块外部的 APK 进行任何修改都会使 APK 的 v2+ 签名失效。剥离了 v2+ 签名的 APK 也将被拒绝,因为它们的 v1 签名指定 APK 已使用 v2 签名,这使得 Android 7.0 及更高版本拒绝使用其 v1 签名来验证 APK。
如需详细了解 APK 签名验证流程,请参阅 APK 签名方案 v2 的验证部分。