iOS app签名机制

前言

在移动开发中,iOS系统下的app和andorid系统下的app一个很大的区别是:android系统下,app的安装很方便,可以从多个应用商店下载(小米应用商店、华为应用商店),也可以直接下载apk的包安装。而在iOS系统下,对app的安装限制比较严格,非开发的app,只能从App Store下载。即使是开发人员,拥有开发者帐号,所开发的app 也不能随意的安装,有最多100台设备的限制,还需要知道设备的UDID……苹果这样做的目的是保证每个app都是经过检验的,都是经过苹果官方审核允许的。那么苹果是如何做到这一点的呢?这就和本文要介绍的内容相关,iOS app的签名机制。
在介绍iOS app签名机制之前,先介绍一些关于加密的知识。

常用的加密方式

目前主流的加密方式有对称密钥加密和非对称密钥加密。

对称密钥加密

维基百科中对对称密钥加密的定义如下:

对称密钥加密(英语:Symmetric-key algorithm)又称为对称加密、私钥加密、共享密钥加密,是密码学中的一类加密算法。这类算法在加密和解密时使用相同的密钥,或是使用两个可以简单地相互推算的密钥

简单来说,就是加密方和解密方使用的是同一个密钥。
常见的对称密钥加密有AES、DES 等。

非对称密钥加密

非对称密钥加密,又称为公开密钥加密。
非对称密钥加密需要两个密钥,一个是公开密钥,一个是私有密钥。私有密钥用来加密,公开密钥用来解密。私有密钥由加密方保管,公有密钥则公布出来。
实际上,私有密钥和共有密钥在数学上是有一定的关系的。但是仅仅从共有密钥是推断不出私有密钥的,这也是共有密钥可以公布出来的原因。
通过共有密钥推断私有密钥和质数分解有关。目前质数分解没有特别快的算法,通常是通过暴力枚举的方法来分解。当质数非常大时(如2的1024次方级别),暴力分解质数是不现实的,因此非对称加密是安全的。
非对称加密的安全还依赖于加密方对私钥的管理,一旦私钥暴露,也就毫无加密可言。
常见的非对称加密有RSA、DSA。

MD5加密

MD5全称MD5消息摘要算法(MD5 Message-Digest Algorithm)。严格来说,MD5并不是一种加密方式,MD5只是一个哈希算法,对同一个明文生成的密文(哈希值)是统一的。MD5相较于普通加密来说还有一个优点:MD5生成的密文长度很短(16位或者32位字符)。

数字签名

了解了常用加密方式之后,介绍一下数字签名,数字签名实际上和生活中的签名效果一致。想一下工作中的报销,报销单只有经过领导签名之后,递交给财务,财务才会发对应的钱。这里的领导签名实际是保证了两件事:
1. 这笔钱的花销是合理的,应该报销
2. 这笔钱的数目是正确的
即:数据是正确的,且是领导认可的。
现实生活中这样做当然是没有问题的,然而在网络上呢,比如客户端请求服务器的数据,如何确认数据中间没有被篡改过?肯定不能像现实中使用笔来签名,于是就有了数字签名。
数字签名和现实生活中签名的作用是一致的,即:
1. 保证数据没有没有被篡改过
2. 保证数据是经过我认证的
数字签名是如何保证上述两点的呢?使用的是非对称加密+MD5线性加密。
数字签名的过程如下:

1. 首先算出原始数据的摘要。这里的算法要保证:如果原始数据有任何变化,则摘要也会发生变化;对同一份原始数据,使用相同的算法,计算出的摘要是相同的。这一步使用的算法通常是MD5消息摘要算法。
2. 生成一对公钥和私钥,使用非对称加密方式,用私钥对上一步生成的摘要进行加密,加密的结果就是数字签名。
3. 在返回数据时,将原始数据和数字签名一起返回给请求数据方。
请求数据方在接收到数据之后,如何确认数据正确以及数据是合法的呢?请求数据方含有公钥,会对数字签名进行验证,过程如下:

1. 首先用含有的公钥对数字签名进行解密,如果能够解密成功,说明返回的数据是经过数据发送方认证的(否则数据发送方不会对该数据加密)。
2. 对原始的数据使用MD5算法,生成原始数据的摘要。
3. 对比第一步和第二步生成的摘要,如果生成的摘要相等,说明原始数据没有被篡改过。
由此,通过数字签名可以达到确保数据没有被篡改过以及数据是合法的目的。

通过AppStore下载的app签名机制

了解了数字签名之后,来看下苹果是如何通过AppStore确保app合法的。
我们都知道,iPhone只有一家生产商,iOS系统只有一个开发者,那就是苹果公司。因此苹果公司可以在所有的iOS系统中做一些统一的事情。实际上,苹果公司生成了一对私钥和公钥,每一个iOS 系统上都内置有公钥,而私钥保存在苹果后台上。开发者再将app上传到苹果服务器之后,苹果公司使用私钥对app进行数字签名。用户从AppStore 下载的app,既包含app包,也包含数字签名。下载到本地后,iOS 系统使用公钥验证签名,就可以确定该app 是经过苹果公司认证的,且包没有被篡改过。整个流程如下:

如果app仅仅只能从AppStore下载安装,那无疑是非常简单的。实际上,除了从AppStore下载安装,开发者还可以通过Xcode打包来安装,打好的包还可以安装在100台设备上,那么这些是如何控制的呢?

通过Xcode将app安装到手机上

在申请成为苹果开发者之后,可以通过Xcode将开发的app安装到手机上,实际上,即使是开发时的app,也需要通过苹果的验证。对于开发时app的安装,苹果使用的是双层验证。先看一些其他的知识。

CertificateSigningRequest文件

申请成为苹果开发者之后,需要在开发者后台上传 CertificateSigningRequest文件,那么CertificateSigningRequest 到底是什么呢?
CertificateSigningRequest 实际上是本地Mac 生成的公钥文件。
Mac可以通过钥匙串访问中的从证书颁发机构请求证书生成一对公钥、私钥。如下图:

生成的CertificateSigningRequest文件里面保存的是公钥,私钥保存在本地Mac 中。

p12文件

在工作中,通常是多个同事共同开发一个app,每个人都可以安装app到真机上。多个人共同开发一个app时,就需要公用一份p12文件。那么p12文件又是什么呢?
p12其实就是保存在本地Mac的私钥。本地Mac的私钥可以导出,导出后的文件即为p12文件。如下图:

双层签名机制

双层签名的流程如下:

1. 在本地Mac 生成一对公钥、私钥
2. 苹果生成一对公钥、私钥。其中私钥在苹果后台管理,每台iOS设备中都有公钥。
3. 将本地Mac生成的公钥(CertificateSigningRequest)上传至开发者后台,在这个过程中,苹果会使用私钥对该公钥进行签名,最后生成一个证书文件。该证书文件中包含公钥L的原始数据,以及签名信息。开发者需要将该证书下载到本地的Mac。
4. 在开发阶段,将app安装到手机上时,使用本地Mac的私钥(p12文件)对app进行签名,最终打包到手机上的有 App原数据,使用本地私钥对app加密后的签名文件,以及上一步下载的证书文件。
5. iOS 设备使用公钥A验证证书中的签名,如果验证通过,说明该公钥是经过苹果认证的(也就是证实了开发者身份)。
6. 之后使用证书中的公钥L 验证App 签名,如果验证通过,说明该app 的安装是合法的。
这样,通过两次验证,间接验证了app的安装是经过苹果允许的。
通过上述的双层验证,只是保证了某app的安装是经过苹果允许的,实际上苹果还有更多的限制:
1. 只有属于开发者开发的app 才被允许安装
2. 开发者开发的app不能被随便安装,最多只能安装到100台设备上。
为了达到上述两个目的,上面流程中在使用私钥A对本地公钥加密时,还有一些其他的信息,如AppID,设备列表等。加上额外信息的流程如下:

主要变化在第3步。使用私钥加密生成数字签名时,不仅仅是本地的公钥,还包括在开发者后台设置的AppID和设备列表。
第5步验证时,如果签名验证通过,说明本地的公钥是经过苹果认证的,且设备列表和AppID 没有被篡改过。
第6步验证时,除了验证App签名,还要验证该设备是否在设备列表中,AppID是否正确等信息。
通过这些附加的信息,就限制了安装数量,避免被滥用。
这也是为何当在开发者后台添加新的设备UDID 时,需要更新证书的原因。因为重新添加了UDID,苹果会重新用私钥加密,重新生成一个新的证书。
到这一步,我们基本上理解了iOS app的签名机制。通过上面的介绍,可以看到第三步生成的证书是非常复杂的,包含了非常多的信息。实际上,除了上述的内容,还有一些推送等权限也需要控制,这些数据也需要签名验证。如果再加上这些信息,证书会变的非常复杂,而且证书也是有一些固定格式的,太多的内容也不符合证书的格式。为了解决这个问题,苹果又搞了个Provisioning Profile文件(也就是俗称的pp文件)。Provisioning Profile文件中除了包含证书,还包含设备列表、AppID、各种权限控制等。
对于各种权限的控制,苹果也统一的处理了一下,叫做Entitlements 文件。
最终的流程也就变成了下面这样:

实际的开发环境中,在将本地的公钥传到开发者中心后,在开发者中心配置设备列表、AppID、以及各种权限控制,之后苹果使用自己的私钥对这些数据进行签名,生成Provisioning Profile文件。开发时,需要将Provisionging Profile文件下载到本地,通过Xcode打包时,会将Provisioning Profile 文件也一起打包进app中。

结语

本文通过引入常见的加密方式,到数字签名,由浅入深介绍了iOS app签名的机制。本文参考了微信阅读的一篇博客加上自己的理解,包括所使用的插图均来自该博客。如果有理解不对的地方,欢迎大家留言交流。

参考文章

https://wereadteam.github.io/2017/03/13/Signature/

猜你喜欢

转载自blog.csdn.net/tugele/article/details/78868236