iOS 应用签名原理

欢迎访问我的博客原文

不少果粉对 Apple 钟情,与它的纯净、安全有很大关系,我们发现在苹果的设备上下载应用时,不会出现触发下载一系列垃圾软件的情况,而且用户可以明确 App 的来源——通过官方商店 AppStore 购买、企业证书安装还是 TestFlight 下载。为了防止盗版软禁、病毒入侵、静默安装以及屏蔽其它不可控因素,并确保每一个安装到 iOS 设备上的应用都是被官方允许的,苹果设定了一套应用签名机制

数字签名

数字签名,又称公钥数字签名,是只有信息的发送者才能产生的别人无法伪造的一段数字串,发送者对要发送的数据打上签名标记,表示这份经过认证,未被篡改的。

数据传输

下面模拟一下数据传输的过程:

  1. 假如发送方直接将原始数据明文传输给接收方时,数据非常不安全,极易被篡改;

  2. 为了提升安全性并同时简化明文,可以对数据进行哈希算法处理,得到原始数据的摘要,然后将摘要发送给接收方。但假如哈希算法被泄漏,依然存在数据被篡改的风险;

  3. 引入非对称加密算法,对一份数据,用哈希算法计算出摘要后,再用 RSA 的私钥加密摘要,得到原始数据的数字签名,发送方将数字签名与原始数据一起发送给接收方

我们将原始数据进行哈希加密、非对称加密后的数据称为数字签名

接收方拿到数据后,需要进行签名验证,来确保数据传输过程中,未被篡改。

数字签名验证

签名验证的具体步骤如下:

  1. 接收方拿到数据后,通过同样的哈希加密处理原始数据,得到哈希值(摘要);

  2. 再利用非对称将数字签名中的校验哈希值(摘要)解密出来;

  3. 最后对比两个哈希值是否一致,判断出数据是否被篡改。

用一张图还原数字签名的完整过程:

iOS 应用签名原理_第1张图片
image

再来看看如何利用数字签名保证每个安装到 iOS 上的 App 都被苹果认证允许。

代码签名

代码签名就是对可执行文件或脚本进行数字签名,用来确认软件在签名后未被修改或损坏的措施。它的原理和数字签名类似,只不过把签名的不是数据,而是代码。

简单的代码签名

假如 App 是只能从 App Store 上下载,那么它的验证方式就比较简单了。

由苹果官方生成一对公私钥,在 iOS 系统中内置一个公钥,私钥由苹果后台保存。

我们把 App 上传到 App Store 时,苹果后台用私钥对 App 数据进行签名,iOS 系统下载这个 App 后,用公钥验证这个签名,如果签名正确则这个 App 肯定是由苹果后台认证的,并且没有被修改或损坏。

iOS 应用签名原理_第2张图片
image

但 iOS 设备安装 App 并不只有 App Store 这一个渠道,比如开发者的真机调试、TestFlight 内测、In-House 企业证书分发等,此时简单的代码签名就无法满足对 App 的完全验证了。

iOS 代码签名的复杂度需要相应增加,于是双层代码签名(双重签名)产生了。

双层代码签名

“双层”意在用两对公私钥做加密验证,它们分别是 Mac 本地的一对和 Apple 服务提供的一对。

双层代码签名的存在是为了满足:

  • App 需要经过苹果允许才能安装;
  • 在 Apple 后台中注册过的设备才能安装,比如在 TestFlight 内测、真机调试模式下;
  • 限制签名只能对应唯一的 App。

为了猜测完整的签名流程,我们可以解压一个 ipa 文件,在 Payload 目录中有一个 embedded.mobileprovision,我们称之为描述文件,它对应的是 Apple 后台生成 Provisioning Profile(简称 PP)文件。文件中包括:

  • 证书(公钥、签名)
  • App ID
  • Entitlements(权限)
  • 注册设备列表
  • 其它关乎 App 能否正常启动的所有信息

所以我们猜测签名的大概流程是这样的:

  1. 在开发设备 Mac 上本地生成一对公私钥。

  2. Apple 有一对公私钥,Apple 私钥在 Apple 后台,Apple 公钥在每台 iOS 设备上。

  3. 把 Mac 公钥上传到 Apple 后台,用 Apple 私钥签名 Mac 公钥,可以得到一份 Mac 公钥和签名的组合数据,我们把这份数据称为证书

  4. 在 Apple 后台申请 App ID,配置好的 UDID(注册设备) 列表以及 App 申请的权限(Entitlements),再加上步骤3中的证书,组合起来的数据用 Apple 私钥进行签名,把数据和签名一起组成 PP 文件,下载到本地的开发设备 Mac 上。

  5. 当我们编译工程时,Mac 私钥会对 App 进行签名,同时把步骤4得到的 PP 文件打包进去,文件名为 embedded.mobileprovision,准备将 App 安装到手机上。

  6. 安装时,iOS 系统取得证书,通过系统内置的 Apple 公钥,去验证证书里的签名是否正确。

  7. 继续用 Apple 公钥验证描述文件是否正确。

  8. 用 Mac 公钥验证 App 签名是否被篡改。

iOS 应用签名原理_第3张图片
image

上面的步骤对应到实际操作和概念是这样的:

第 1 步:Mac 上依次打开“钥匙串访问 → 证书助理 → 从证书颁发机构请求证书...”,做了这一步,就会在本地生成了一对公私钥,导出的 CSR 文件(CertificateSigningRequest.certSigningRequest)就是 Mac 公钥,Mac 私钥也是存储在本地,具体是什么文件看第 3 步。

第 2 步:每台 iOS 设备中都已经有了 Apple 公钥,至于 Apple 私钥是什么,看第 3 步。

第 3 步:在 Apple 后台的 iOS Certificates 模块,通过上传本地导出的 CSR 文件,生成 .cer 证书文件,也就是 Apple 私钥。将 .cer 证书下载到本地,安装证书,在钥匙串中找到证书,就可以导出 Mac 私钥,也就是一个 .p12 文件。它和第 1 步中导出的 Mac 公钥是对应的,钥匙串会把这两个证书关联起来。用.cer 证书去签名 CSR 文件,拿到含有签名的证书。

第 4 步:在 Apple 后台配置 App ID、Entitlements、Devices 等,然后下载 PP 文件。

第 5 步:编译 App 时,Xcode 会通过第 3 步下载回来的证书(存着 Mac 公钥),在本地找到对应的 Mac 私钥,然后用 Mac 私钥去签名 App,同时打包,安装包中包含 PP 文件,在 ipa 中的文件名是 embedded.mobileprovision。这里 App 的签名数据被分为两部分,Mach-O 可执行文件会把签名直接写入描述文件里,而资源文件则会保存在 _CodeSignature 目录下,这时准备安装 App。

第 6 步:使用 Apple 公钥验证描述文件签名,对应第 4 步,签名通过,说明证书可用,进入下一步。

第 7 步:使用 Apple 公钥验证证书签名,对应第 3 步,签名通过,说明 Mac 公钥合法,进入下一步。

第 8 步:使用 Mac 公钥验证 App 签名,对应第 4 步,上述验证均通过后,还需要将描述文件中的内容与 App 本身的信息做验证对比,比如验证设备 ID 是否在 UDID 列表上,App ID 是否相同,权限开关是否与 Entitlements 一致,都验证通过,就可以开始安装 App。

前面说了,双层代码签名是针对开发测试包、In-House 企业签名、Ad-Hoc 包为例的签名和验证的流程,只是企业签名不限制安装的设备数,因此描述文件中不会有设备列表,而是一条 ProvisionsAllDevices 记录。

而从 App Store 上下载的安装包,里面是没有描述文件的,但上架之前还是要配置证书、PP 文件,因为 App ID 和权限的检验还是需要做的。但 App 上传到 AppStore 以后就跟 PP 文件没有关系了,所以我们可以理解为 App Store 上包的签名验证采用就是前面说的最简单的签名方式,Apple 后台直接用私钥签名 App 就可以了。

你可能感兴趣的:(iOS 应用签名原理)