在讨论关于iOS应用签名之前,我们需要先了解一个东西,叫做数字签名
数字签名
名词解释:因为老外喜欢用支票,支票上面的签名能够证明这玩意是你的。那么数字签名顾名思义,就是用于鉴别数字信息的方法。
接下来我们思考一下.想要证明数字信息(也就是二进制数据,计算机里面的任意数据)的有效性,那么使用什么方式最合适呢?
我们可以想到有"信息指纹"之称的HASH算法,在之前的文章中有讲到HASH算法专门用来做文件数据的识别.那么在网络数据传递的过程中,我们可以将明文数据,和数据的HASH值一起传递给对方.对方可以拿出HASH值来进行验证.
[图片上传中...(image.png-2d917e-1646570440545-0)]
但是在这个过程中,如何做到数据的保护呢?明文数据和HASH值如果直接传递就有都被篡改的风险.所以这里我们要对数据进行加密.明文数据有时会比较大,不适合使用RSA非对称加密算法,那么数据的HASH值是比较小的.这个数据是用于校验的,它完全可以使用RSA来加密.所以在数据传递的时候,我们将明文数据加上通过RSA加密的校验数据一并传递给对方.那么这个通过RSA加密的校验数据,我们称之为签名.
数字签名的验证过程
当对方拿到数据之后,如何进行验证呢?
首先传递数据时会将原始的数据和数字签名一起发送
对方拿到数据后,先进行校验.拿到原始数据,通过同样的HASH算法得到数据的HASH值.
然后通过非对称加密,将数字签名中的校验HASH值解密出来.
最后对比两个HASH值是否一致.这样可以很好的判断数据是否被篡改!
代码签名
代码签名是对可执行文件或脚本进行数字签名。用来确认软件在签名后未被修改或损坏的措施。和数字签名原理一样,只不过签名的数据是代码而已
在iOS出来之前,以前的主流操作系统(Mac/Windows)软件随便从哪里下载都能运行,系统存在安全隐患、盗版软件、病毒入侵、静默安装等等。那么苹果公司希望解决这样的问题,要保证每一个安装到iOS上的APP都是经过苹果官方允许的,那么怎么保证呢?就是通过代码签名。
如果要实现验证,其实最简单的方式就是通过苹果官方生成的非对称加密的一对公私钥。在iOS系统中内置一个公钥,私钥由苹果服务器保存,我们传App到App Store时,苹果服务器用私钥对App数据进行签名,iOS系统下载这个App后,用公钥验证这个签名,若签名正确,这个App肯定是由苹果服务器认证的,并且没有被修改过,也就达到了苹果的需求,保证了每个App都是经过苹果官方允许的。
如果我们的iOS设备安装App只从App Store这一个入口安装的话,那么这件事就很简单的解决了,没有任何复杂的东西,一个数字签名搞定。
但是实际上iOS安装还有其他的渠道,比如对于我们开发者iOSER而言,我们是需要在开发App时直接进行真机调试的,而且苹果还开放了企业内部分发的渠道,企业证书签名的App也是需要顺利安装的。
苹果需要开放这些方式安装App,这些就无法通过简单的代码签名来办到了。
为了实现这些需求,iOS签名的复杂度也就开始增加了,苹果这里给出的方案是双层签名。
双层代码签名
iOS的双层代码签名流程这里简单梳理一下,这也不是最终的iOS签名原理。iOS的最终签名在这个基础上还要稍微加点东西。
首先这里有两个角色。一个是iOS系统,还有一个就是我们的Mac系统。因为iOS的APP开发环境在Mac系统下,所以这个依赖关系成为了苹果双层签名的基础。
双向签名的过程如下:
1、在Mac系统中生成一对公钥和私钥,这里称为公钥M和私钥M。(M=Mac)
2、苹果自己有固定的一对公钥和私钥,跟之前App Store原理一样,私钥在苹果后台,公钥在每个iOS系统中。这里称为公钥A和私钥A。(A=Apple)
3、把公钥M以及一些开发者的信息,传到苹果后台(这个就是CSR文件),用苹果后台里的私钥A去签名公钥M。 得到一份数据包含了公钥M以及其签名,把这份数据称为证书。
4、在开发时,编译完一个App后,用本地的私钥M(P12)对这个App进行签名,同时把第三步得到的证书一起打包进App里,安装到手机上。
5、安装时,iOS系统进行2次签名验证:
- 通过系统内置的公钥A解密证书私钥A获取证书摘要,再验证证书是否被篡改。
- 验证证书后确保了公钥M是苹果认证过的,再用公钥M去验证App的签名。
有了上面的过程,已经可以保证开发者的认证,和程序的安全性了。 但是,iOS程序一般是通过App Store分发到用户设备的。如果只有上述的过程,那岂不是只要申请了一个证书,就可以安装到所有 iOS设备了?
苹果这里给出的方案是授权文件。
描述文件
苹果为了解决应用滥用的问题,又加上了一些限制:
- 苹果后台注册过的设备才可以安装。
- 签名只能针对某一个具体的App。
- 苹果还想控制App里面的iCloud、Push、后台运行、调试器附加这些权限,所以苹果把这些权限开关统一称为Entitlements(授权文件)。将这个文件放在了一个叫做Provisioning Profile(描述文件)文件中,Xcode运行时会打包进入App内。
在开发时,编译完一个 App后,用本地的私钥M对这个App进行签名,同时把从苹果服务器得到的描述文件打包进APP里,文件名为embedded.mobileprovision。App安装到手机上后,系统将完成验证工作。
我们可以利用$security cms -D -i embedded.mobileprovision命令查看Provisioning profile内容,这些Xcode创建的Profile文件都存放在~/Library/MobileDevice/Provisioning Profiles/目录下:
注意:每次我们新建项目其实会生成一个描述文件,选择运行到手机上!我们只需要编译一下,在APP包里面就可以看到。
整体的流程
首先我们总结一下刚才的一些名词
-
证书:内容是公钥或者私钥,由认证机构对其签名组成的数据包!我们开发可以使用钥匙串访问看到
P12:就是本地私钥,可以导入到其他电脑
Entitlements:权限文件,包含了APP一些权限的plist文件
CertificateSigningRequest:CSR文件包含了本地公钥的数据文件
Provisioning Profile:描述文件,包含了证书/Entitlements等数据,并由苹果后台私钥签名的数据包.
流程如下:
第 1 步对应的是 keychain 里的 “从证书颁发机构请求证书”,这里就本地生成了一对公私钥,保存的 CertificateSigningRequest 里面就包含公钥,私钥保存在本地电脑里.
第 2 步向苹果申请对应把 CSR 传到苹果后台生成证书.
-
第 3 步证书下载到本地.这时本地有两个证书.一个是第 1 步生成的私钥,一个是这里下载回来的证书,keychain 会把这两个证书关联起来,因为他们公私钥是对应的,在XCode选择下载回来的证书时,实际上会找到 keychain 里对应的私钥去签名.这里私钥只有生成它的这台 Mac 有,如果别的 Mac 也要编译签名这个 App 怎么办?答案是把私钥导出给其他 Mac 用,在 keychain 里导出私钥,就会存成 .p12 文件,其他 Mac 打开后就导入了这个私钥.
第 4 步都是在苹果网站上操作,配置 AppID / 权限 / 设备等,最后下载 Provisioning Profile 文件。
第 5 步 XCode 会通过第 3 步下载回来的证书(存着公钥),在本地找到对应的私钥(第一步生成的),用本地私钥去签名 App,并把 Provisioning Profile 文件命名为 embedded.mobileprovision 一起打包进去。所以任何本地调试的APP,都会有一个embedded.mobileprovision(描述文件)从App Store下载的没有.
APP签名的数据
这里对 App 的签名数据保存分两部分
-
1.Mach-O 可执行文件会把签名直接写入文件里
2.其他资源文件则会保存在 _CodeSignature 目录下在APP包里。
至此关于iOS应用签名的原理就介绍完了.下篇文章将介绍iOS应用重签名技术.