签名过程类似于对文件办法数字证书。签名后的APK文件在安装时,Android系统会对其进行验证,以确保文件未被篡改且来自“可信的开发者”。“可信的开发者”我打上了双引号,因为默认的情况下安卓没有办法判断开发者是否可信。
签名机制
APK签名的原理基于公钥加密和数字证书的机制。具体来说,签名过程包括以下几个步骤:
- 生成密钥对:开发者使用密钥生成工具(如keytool)生成一对公钥和私钥。公钥用于验证签名,私钥用于生成签名。
- 计算摘要:开发者使用哈希算法(如SHA-256)对APK文件的内容进行计算,得到一个固定长度的摘要。这个摘要是APK文件内容的唯一表示。
- 生成签名:开发者使用私钥对摘要进行加密,生成签名文件。签名文件通常包含签名数据、公钥以及开发者证书等信息。
- 添加签名文件:开发者将签名文件添加到APK包中,通常放在META-INF目录下。
上面的签名过程只是一个非常非常简单的描述,具体不同签名版本实现的机制有些不同。
签名范围
签名过程中是否对所有文件都进行了签名计算,是不是APK改动了任意一个字节签名就会不通过?
在签名过程中,并非对所有文件都直接进行了签名计算,而是采用了特定的签名机制来确保APK的完整性和来源的可靠性。具体来说,Android APK的签名过程大致如下:
- 计算Hash值:首先,对未签名的APK里面的所有文件(除了META-INF目录,这个目录通常用于存放签名信息)计算hash值。这一步骤是为了生成每个文件的唯一摘要,以便后续进行验证。
- 保存Hash值:计算得到的hash值会被保存在一个名为MANIFEST.MF的文件中。这个文件记录了APK中每个文件的hash值,但不包括META-INF目录本身。
- 再次计算Hash值并签名:接着,对MANIFEST.MF文件本身也计算hash值,并将这些hash值以及MANIFEST.MF文件本身的信息保存在CERT.SF文件中。然后,使用开发者的私钥对CERT.SF文件(或其中的hash值)进行签名,并将签名结果保存在CERT.RSA文件中。
关于APK改动后签名验证的问题:
- 改动任意一个字节:如果APK中的任何一个文件(除了META-INF目录下的文件)被改动,那么该文件的hash值将会发生变化。在安装或升级过程中,系统会重新计算APK中所有文件的hash值,并与MANIFEST.MF中记录的hash值进行比较。如果发现有任何不匹配的情况,签名验证将会失败,导致APK无法安装或升级。
- META-INF目录的改动:虽然META-INF目录下的文件本身通常不包含APK业务逻辑的代码或资源,但直接修改这个目录也可能会影响签名的验证。因为系统可能会检查META-INF目录下文件的完整性和签名信息的一致性。然而,在某些情况下,如添加空目录或特定类型的文件到META-INF目录下,可能不会影响原有的签名验证(但这并不是一种推荐的做法,因为它可能引入未知的风险)。
不同签名版本之间的比较
签名版本 | V1 (JAR签名) | V2 (APK签名方案v2+) | V3 (APK签名方案v3+) | V3.1 (APK签名方案v3.1+) | V4 (APK签名方案v4+) |
---|---|---|---|---|---|
引入的Android版本 | 早期版本 | 7.0 (API 24) | 9.0 (API 28) | 13 | 11.0 |
签名机制 | 整体签名 | 增量签名 | 增量签名 | 增量签名 | 基于Merkle哈希树 |
哈希算法 | MD5, SHA1 | SHA256 | SHA256 | SHA256 | Merkle哈希树 |
签名算法 | RSA, DSA | ECDSA | RSA, ECDSA | RSA, ECDSA | – |
增量签名 | 否 | 是 | 是 | 是 | – |
安全性增强 | 基础 | 高效验证、更广覆盖范围 | 更强大签名算法、密钥轮替支持 | 解决V3轮替问题,支持SDK版本定位 | 支持ADB增量APK安装 |
兼容性 | 所有Android版本 | 与V1兼容 | 与V1、V2兼容 | 与旧版Android兼容 | 需要v2或v3签名作为补充 |
主要用途 | 早期应用的签名 | 提高验证性能和完整性保证 | 提供更高的安全性,支持密钥轮替 | 改进V3签名方案,增强密钥轮替支持 | 开发调试场景,支持ADB增量安装 |
应用市场签名机制对比
由于安卓在安装APP时仅将APK中的签名与证书校验,意思就是仅能保证这个APK是由这张证书的所有者提供且没有被篡改的。但用户又如何判断这张证书就是正规来源的证书呢?其实没有办法,证书上只提供了所有者的一些基本信息,比如名称,这个名称是在创建证书时随意起的,所以没有任何说服力。
而苹果应用市场那边就不同了:
iOS应用商店:
- 开发者在苹果开发者中心创建证书和描述文件。
- 证书用于证明开发者身份,并与私钥配对用于签名应用程序。
- 描述文件用于授权安装应用程序,包含应用程序ID、设备UDID列表和证书信息。
安卓应用商店:
- 开发者自行生成签名证书(如使用keytool工具),并将其用于对APK文件进行签名。
- 签名证书由开发者保管,并在需要时用于签名新的APK版本。
可以看到一个明显的区别就是苹果的证书是官方统一管理的,至少在一定程度上能控制开发者的合法性,比如上传认证资料等。而安卓这边,开发者自行生成证书,虽然通过签名技术保证了完整性,但真实性没有保护,最后完整性也得不到保障。
所以现在各手机品牌陆续推出自己的应用市场,效仿苹果的那种模式,APK采用统一办法的证书签名才能上应用市场,比如华为应用市场、小米应用市场等。
0