iOS 签名机制

私自安装的程序为何不能运行?XX 助手下载的应用为何频频闪退?codesign failed 究竟是何人所为?missing private key 又是怎么回事?流氓公司集体从良的背后又隐藏着什么?这一切的背后,是 XX 还是 XXX 。。。。咳咳,编不下去了(๑•̀ㅂ•́)و✧,反正只要明白本文是讲 iOS 的签名机制就对了。

但是在讲解签名机制之前,我们需要搞清楚它为什么会存在?苹果为什么要花费这么大的精力来建立签名机制?这需要我们从苹果公司的角度来思考下面的问题:

  • 用户下载应用的过程中被黑客攻击了,程序遭到了篡改,用户的个人隐私遭到泄漏,财产也遭受损失,怎么办?

  • 开发者呕心沥血开发出了一款应用,结果发布之后盗版横行,盗版商发了一笔大财,开发者却饿死家中,怎么办?

  • 流氓应用遍地跑,互相唤醒,全家桶安装,无底限收集用户隐私,卸都卸不掉,用户苦不堪言,怎么办?

  • ……

以上都是很现实的问题,所以苹果公司为了避免发生这些情况,就必须做到对 app 的安装具有绝对的控制权,也就是只有被苹果认可的应用才可以安装到用户的手机上,而 iOS 的签名机制就是为了这一目的建立的(同时还有 App Store 以及应用审核机制)。这些机制带来了非常多的好处,包括确保应用不被篡改、盗版应用无法运行、流氓厂商面临要么下架要么从良的选择等等,这不仅使苹果的应用生态能够健康可持续的发展,也保证了用户以及开发者的利益。

非对称加密算法

非对称加密算法是 iOS 签名机制的基础,它使用两份密钥(公钥、私钥)来对信息进行加密以及解密:对外公开的密钥为公钥,签名方自己持有的密钥为私钥,通过私钥加密的内容只能用公钥解密,而通过公钥加密的内容也只有私钥能够解密。由于通过公钥反推私钥的难度非常大,理论上只要密钥的位数足够长,反推基本是不可能的,所以非对称加密算法是被广泛使用的安全性非常高的加密算法。

常用的非对称加密算法有 RSA、ECC、Diffie-Hellman 等,以下几篇文章是介绍 RSA 算法的,感兴趣的同学可以了解下:RSA原理与实例RSA算法原理(一)RSA算法原理(二)

Hash 算法

由于非对称加密算法对明文的长度有要求,即不能超过密钥的长度,所以在使用非对称加密算法之前,会使用 Hash 算法对明文进行处理。

任意长度的明文在经过 Hash 算法处理后,都会得到一串长度固定的 Hash 值,并且整个过程是不可逆的,因此 Hash 算法常被用来处理关键数据。常见的 Hash 算法有:MD5SHA-1SHA-2 等。

App Store

那么签名机制是如何保证用户下载的应用是被苹果认证的呢?在 iOS 设备上,App Store 是用户下载应用的唯一渠道,苹果公司建立这一渠道的目的就是为了获得应用生态的控制权。开发者在上传应用后,苹果公司会对应用进行非常严格的审核,只有通过审核才可以进入 App Store 展示给用户。审核通过后,苹果公司会按照下图所示的步骤生成应用的签名:

  1. 首先使用 Hash 算法对 App 数据进行处理,得到摘要

  2. 接下来会使用 Apple 私钥对摘要进行加密,得到签名

用户在 App Store 上购买应用后,签名会和 App 一起下载到用户的手机上,接下来用户的 iOS 设备会进行如下处理:

  1. 使用相同的 Hash 算法对下载到用户手机的 App 进行处理,得到摘要1

  2. 使用 Apple 公钥对签名进行解密,得到摘要2(Apple 公钥是事先内置在 iOS 设备中的)

  3. 判断摘要1和摘要2是否相等,如果相等,那么认证成功,App 可以安装,否则认证失败,App 无法安装

开发者视角

上述认证流程可以满足一个普通用户的需求,但却无法满足开发者。因为开发者在开发应用的过程中会无数次的在手机上调试 app,如果每次安装应用时都要上传到苹果那边签名,然后再下载,这是无法接受的,所以苹果又为开发者建立了独特的本地签名的流程。

开发者会在自己的电脑上生成用于签名认证的公钥和私钥,以后安装 app 到手机上时会在本地进行认证,而无需将 app 上传到苹果的服务器上签名。但是苹果也必须要维护自己控制 app 安装的权利,那么苹果会怎么做呢?答案就是使用数字证书。

数字证书

开发者通过 钥匙串访问->证书助理->从证书颁发机构请求证书 生成 Certificate Signing Request 文件(CSR 文件),同时也在本地自动生成了相应的公钥和私钥,在填好必要的信息后,开发者将 CSR 文件上传给苹果用于生成数字证书。

CSR 文件记录了开发者的个人信息、公钥、加密算法以及 Hash 算法等内容,可以使用以下命令来查看文件内容:

苹果收到 CSR 文件后,会使用自己的私钥对开发者的公钥进行签名,最终生成一个数字证书(包含开发者账号信息、公钥以及相应的签名)返回给开发者,查看证书信息的命令如下:

点击安装证书后,钥匙串会自动将证书和相应的私钥对应起来,同时你还需要在 Xcode 中将签名证书设置为你刚刚安装的证书。此后在编译完 app 时,系统会使用数字证书对应的本地私钥对 app 进行签名,然后同数字证书一起安装到手机上,接下来 iOS 设备会通过 Apple 公钥来验证数字证书是否有效,验证通过后会使用数字证书中的公钥来验证 app 是否有效,最终判断 app 是否可以被安装。

Provisioning Profile

仅有数字证书是不够的,为了防止权限被滥用,开发者还需要在苹果官网上注册用于开发的设备,仅有注册后的设备才被允许按照以上流程安装 app。

个人开发者账号可以注册的设备是100台,Enterprise 账号不限制数量,但是不能将应用发布到 App Store 上,关于开发者账号的种类以及区别可以参考 Choosing a Membership

除此之外,苹果还需要对 app 的权限进行控制,例如是否能够使用 iCloud、Wallet、Maps 等,苹果将这些功能授权统称为 Entitlements。开发者将上述权限配置完成后,需要从苹果后台下载并安装相应的 mobileprovision 文件,该文件包含:

  1. AppId,每个 app 都会有对应的 mobileprovision 文件

  2. 功能授权列表

  3. 已注册的设备列表

  4. 数字证书

  5. 苹果签名

没错,你没看错,苹果对你下载的 mobileprovision 文件也会签名,所以你是无法更改文件内容的。因此你需要注意的是,如果你在 Xcode 中的 Capabilities 开启了 app 的某项功能,那么你一定要去苹果后台更新 app 的权限,然后下载最新的 mobileprovision 安装,否则会有诡异的事情发生。

当然,如果有需要的话,你可以使用以下命令来查看 mobileprovision 文件内容:

app 编译完成之后,也会将 mobileprovision 文件打包到 app 中。

综合上述信息,最终流程是这样的:

  1. 开发者在本地生成私钥和公钥,然后将公钥上传给苹果并获取苹果签名的数字证书

  2. 开发者在苹果后台配置 AppId,注册开发设备,配置功能权限,最后下载并安装 mobileprovision 文件

  3. 开发者用本地私钥签名 app,并将 mobileprovision 文件随 app 安装进 iOS 设备

  4. iOS 设备使用 Apple 公钥验证 mobileprovision 文件的签名以及数字证书的签名

  5. 使用数字证书包含的公钥来验证 app 的签名

  6. 验证安装 app 的设备是否在设备列表中,AppId 是否一致,Entitlements 和 app 中的权限是否对的上等等

其他发布流程

除了 App Store 以及开发者真机调试外,苹果还设置了其他流程来发布应用,包括 In-House 以及 Ad-Hoc。只有 Enterprise 账号才可以进行 In-House 发布,其目的是为了在企业内部使用 app,现在常见的 XX 助手就是使用 Enterprise 账号来发布盗版应用,对于这种滥用行为,苹果只能一个个吊销账号,并没有太好的办法。而 Ad-Hoc 则是用于小范围发布给用户进行测试,限制的数量是100台,参与 Ad-Hoc 的设备必须要事先注册。关于发布流程可以参考这篇文章

补充

你可能听人说过 p12 文件,那么这个是什么呢?p12 文件常用于 iOS 证书共享,你可以在钥匙串中以 p12 格式导出你的本地私钥,配合数字证书、 mobileprovision 文件共享给团队中的其他成员,这样其他人也可以用你的证书开发程序了。

这里再额外提一下,我们最终生成的 app 都是 ipa 格式,里面包含可执行文件、资源文件、第三方 Framework 等,可执行文件的签名会直接保存在可执行文件里,其他文件的签名会放在 _CodeSignature/CodeResources 中,而 Frameworks 内部会包含自身的签名信息。你还可以在 ipa 中找到 embedded.mobileprovision 文件,然而如果你是从 App Store 上下载的 app,那么是没有 mobileprovision 文件的。

如果你想进一步了解苹果签名,你可以参考以下文档:Code Signing GuideApp Distribution Guide代码签名探析

发表评论

Close Menu