一 概述
之前我在做iOS项目开发时,由于采用的是自己的开发者账号,在Xcode的General配置中勾选上Automatically manager signing
便再也不用管证书等一些问题,所有的一切都是由xcode自己来给你做。但是当涉及到团队开发,有时候需要共享一个数字证书和mobileprovision文件时,便有层出不穷的问题。尽管有些google一下也能解决,但是并不了解其实质原理,为何要这么做。
如果你对Provision profile
(称为配置文件or描述文件)、CertificateSigningRequest
、P12
、Cer
等等这些证书一知半解,相信本文可以解答你心中的疑惑。
本文会从原理出发,一步步解释iOS签名的各个处理流程,主要章节如下:
- 摘要算法
- 对称加密算法
- 非对称加密算法
- 数字签名
- 数字证书
- iOS签名机制与配置文件
- iOS上build的处理流程
- iOS app从appStore下载的验证流程
- 加密算法在 HTTPS上的应用
二 摘要算法
摘要算法又称为哈希算法,可以将任意长度的数据流通过hash计算,输出固定长度的数据,相同输入的数据始终得到相同的输出。
常用的hash算法有:
MD5
输出长度:128bit
SHA-1
输出长度:160bit
SHA-256
输出长度:256bit
由于输出长度是固定的并且输出输入的长度不固定,这就意味着两个不同的输入可能得到相同的输出,这就是碰撞的问题。所以在设计Hash算法时尽量使其碰撞率低,并且安全的hash算法很难从输入反推出输入,只能依靠暴力穷举。
特征: 不同数据的计算结果不同、不可逆
三 对称加密算法
对称加密,也称单钥加密,同一个密钥可以加密和解密。由于其速度快,对称性加密通常在消息发送方需要加密大量数据时使用。该加密算法的安全性不仅取决于加密算法本身,密钥管理更为重要,如何将密钥安全地传递到解密者手上就成了必须要解决的问题。
常用的对称加密:
-
DES
数据对称加密标准,因为加密强度不够用得少; -
3DES
使用三个密钥对相同的数据进行三次加密; -
AES
高级密码加密,美国安全局使用,Apple钥匙串便采用该种方式。
该算法特点:算法公开、计算量小、加密速度快,但是密钥管理成问题。
四 非对称加密
非对称加密算法是指,加密密钥和解密密钥是不同的,一般加密密钥和解密密钥是成对出现的。公私钥具有以下重要特性:
- 对于一个私钥,有且只有一个与其对应的公钥;
- 公钥是公开的,但是不能通过公钥推导出私钥;
- 私钥加密的文件可用公钥解密,同样公钥加密的文件可用私钥进行解密。
目前使用最广泛的公钥密码算法是RSA。RSA的名字有3位开发者,即Ron Rivest、Adi Shamir、Leonard Adleman的姓氏首字母组成。
非对称加密虽然安全性较高,但是加密速度较慢,不适合对大量数据进行加密.
了解了以上知识点,接下来便是数字签名原理
五 数字签名
数字签名实际上就是将摘要算法和非对称加密算法结合起来,其设计的目的是保证数据文件的完整性,防止中途被中间人篡改。
如上图,当我们手上数据内容需要上传到服务器端,则首先将数据内容采用MD5的hash算法生成一个32个字符摘要,然后在用RSA公钥进行加密生成密文,即数字签名。
而上传到服务器的内容则由数据内容和数字签名构成,服务器拿到数据包后先将数字签名采用RSA的私钥进行解密拿到之前的摘要,再将获取到的数据内容采用md5算法得到该内容的hash摘要值,最后将这两个摘要进行对比,如果一致则数据完好无锁。
note:加密后为128位(bit),按照16进制(4位一个16进制数)编码后,就成了32个字符
这个过程仅对md5加密是为了减少非对称加解密所耗费的时间。数字签名可以快速的验证文本的安全性和合法性。理解了数字签名,可以进一步来理解数字证书。
六 数字证书
签名过程看起来已经足够安全,数据接收方通过发送公钥对签名进行解密,便可以验证发送者的数据完整性和安全性。但是如果接收方手中的公钥已经被中间人劫持,而真正到达发送者手中的公钥是来自于中间人给的,那么这个过程便又不安全,具体过程可以看如下图:
服务器端发送的公钥让中间人劫持了,中间人把自己的公钥发给用户,而用户便用此公钥加密数据发送给服务器,而此时的服务器其实已经是中间人了。中间人再次劫持用户的数据并用自己的私钥解密,然后用真正服务器端的公钥加密自己篡改的数据发送给服务器。
对于这样的问题,有一种目前通用的解决方案。找一个可以信任的数字证书机构(Certificate Authority,CA),将我们的公钥和注册信息交给CA。CA将我们的合法信息和公钥利用非对称加密(CA自己的私钥)生成密文(即数字签名),再将签名和我们的公钥信息打包成证书给我们。下次用户如果需要向我们发送消息,需要先去CA上请求CA公钥,然后我们给用户证书,用户再去用CA公钥解密签名,以此来验证我们给出的公钥是否正确。
数字证书和生活中的证书一样,例如驾驶证、英语四六级证书等等,数字证书的签发机构也有若干,例如苹果公司就可以签发apple开发相关证书,而web相关的证书也有几家国际公认的机构进行签发,这些机构称为CA。
七 iOS签名机制与配置文件
iOS签名机制的作用:保证安装到手机上的app都是经过Apple官方验证和许可的。不管真机调试,还是发布App,开发者都必须经过一些列复杂的步骤,下面我将详细的说明这些。
-
第一步 上传本地开发者的公钥信息到MC
具体操作就是从mac上钥匙串中生成一个CertificateSigningRequest.certSigningRequest
文件,该文件中主要包含以下信息:
- 申请者信息,此信息是用申请者的私钥加密的
- 申请者公钥,此信息是申请者使用的私钥对应的公钥
- 摘要算法和公钥加密算法
可以采用openssl来解析文件中内容:
openssl asn1parse -i -in CertificateSigningRequest.certSigningRequest
为什么要上传这个信息呢?因为后续我们在用xcode构建项目时,需要对可执行文件进行签名(即采用本地摘要算法先进行hash计算,然后在使用本地私钥进行加密),如果MC拿不到我们的公钥,那么如何进行非对称解密,如何验证我们app是否完整呢!
拿到CRS文件后上传到MC。
-
第二步 从MC下载apple颁发的Cer证书
上一步上传完CSR文件后,可以根据我们的需求配置证书相关的信息,例如bundleID,Push、Apple Pay等等,然后我们将MC生成的证书下载并安装到本地钥匙串中,如下图:
其实MC在拿到我们上传CSR文件后,提取里面的公钥,它需要做的便是将MC中关于我的账号信息和刚刚提交的公钥打包,再进行数字签名,最后封装到cer证书中。
我们可以用openssl来看一下cer文件内容:
openssl x509 -inform der -in ios_development.cer -noout -text
也可以直接在mac上按住空格预览,截图如下:
其中主要包含摘要算法和RSA加密公钥,以及一个apple的签名。双击安装证书后,KeyChain子自动将这公钥和本地私钥关联起来。后续程序在真机上build时,会使用本地私钥进行代码签名,而公钥会附带人mobileprovision文件中去,打包进app。
note: 实际上公钥是放在了
mobileprovision
文件中,并不是随代码一同打包的,所以我认为我们mac上安装的证书没有实际用处,因为mobileprovision
是MC为我们生成的。其实安装证书的主要目的应该是区别对应的私钥,真正用于签名的是私钥,如果本地有多个不同的证书,那就有多个私钥,所以需要依靠不同证书来区分到底用哪种私钥进行codesign。mobileprovision
我会在后面讲解。所以,有证书却没有私钥还是没用的。
既然私钥是某台电脑上生成的,那么团队如何开发呢?
其实我们可以从钥匙串中给安装好的证书导出.p12
文件,在其他机器上安装即可共享私钥和证书了。
我们下载下来的证书也是有很多种类的,就好像你需要驾驶证才能开机动车,你需要护照才能出国,用途不同,证书也不同。如下是展示部分证书类型:
- iOS App Development。开发、真机调试用
- Apple Push Notification service SSL (Sandbox)。开发阶段使用苹果的推送服务
- App Store and Ad Hoc。上架和AdHoc方式发布时用
- Apple Push Notification service SSL (Production)。上架后使用苹果推送服务
5.0 In-House。企业版发布,需$299才能拥有,还需邓氏编码
-
第三步 配置iOS mobileprovision文件
证书只保证了app的所属和完整性,却不能保证app的某些功能和服务是被苹果认可的,例如APNs和apple pay等等。所以,苹果想出了坑爹作死的mobileprovision
。
可以用如下命令查看描述文件的内容:
security cms -D -i embedded.mobileprovision
截图如下:
描述文件主要包含了:
- AppId。
- 使用哪些证书。
- 功能授权列表
- 可安装的设备列表。对于AdHoc方式发布的app或者真机调试时,会有一个列表,这个列表里面是iOS设备的UDID,每台iOS设备出厂的UDID都不同。
- 苹果的签名。这里的签名是apple的私钥签名的,不是我们本地的私钥,我们除了从MC中下载,没有其他方法,如果我们篡改了相关信息,则文件失效。因此app的各种权利完全被apple牢牢掌控着。
如果采用Adhoc发布呢?
Adhoc允许将beta版发布给最多100台设备安装,apple便是通过这里描述文件的第四条来牢牢掌控,只需要描述文件中有相关设备的UDID便可以,而这些UDID需要事先添加到MC的Devices中去。
以上便是iOS签名机制和描述文件的详细讲解,下面会继续嗨聊iOS作死的代码签名。
八 iOS上build的处理流程
我们平时用VS或者clion编一些C/C++时,几乎都是走code-build-link-run流程,无需其他什么认证,但是由于apple的严格生态规则,必须要验证开发者身份和权限。
8.1 build
当我们在xcode上进行build时,apple首先去验证开发者,根据用户所选的证书从钥匙串中匹配到相应的私钥,再利用私钥对代码和资源文件签名生成一个_CodeSignature
文件,然后与资源文件、app文件、描述文件、Framework文件一同打包到.ipa
压缩包中。
我们可以打开一个.ipa
压缩包,
unzip -q <name> -d <destination>
显示截图如下:
其中,_CodeSignature文件中保存着一个plist文件,其内容是程序包中所有文件的签名,不包含Frameworks文件的签名。mobileprovision文件是打包时使用的,从MC上生成的。Frameworks文件中是引入的第三方框架,每个框架结构类似一个app,也有自己的代码签名。
8.2 校验
当ipa文件复制到iOS设备上,iOS设备会先拿到描述文件,然后先利用iOS设备本地存储的apple MC的公钥来验证描述文件的签名,已确保描述文件没有问题。之后取出描述文件中的数字证书,同样利用本地apple MC的公钥来验证证书签名,确保证书没有被篡改,没有问题的情况下继续出去证书中保存的Mac本地的公钥,利用公钥来验证_CodeSignature
代码签名文件没有问题,最后按照描述文件中配置的app功能权限检测app是否有越权行为,以上验证都没有问题则可以在iOS设备上安装app了。
8.3 iOS真机调试的整个流程
首先mac设备本地存有公钥私钥,用于加解密项目文件;然后MC上(即apple Member center)存有apple的私钥,用于加密供我们下载使用的数字证书和描述文件;最后在iOS设备上会存着apple的私钥,用于解密描述文件和数字证书中的签名。结构如下图所示:
下图是真机调试的整个流程图:
整个过程主要是围绕App完整性和验证开发者的权限设计的。大致思路如下:
- 将Mac公钥等核心信息上传至MC,MC会用apple私钥签好名一起打包到数字证书中;
- 在MC上配置app权限和任务会生成相应的配置文件,该文件会被MC用apple私钥做签名,然后一起打包放入
mobileprovision
文件中,以供用户下载安装到xcode中; - 当xcode在真机上调试app,我们的代码资源会被mac私钥加密签名生成数字签名,然后与描述文件一起打包进ipa压缩包中;
- iOS设备接收到ipa压缩包,会先用本地存储的apple公钥进行签名验证,查看描述文件是否安全;
- 如果4安全,则提取描述文件中的数字证书,并用apple公钥来验证数字证书是否安全,如果安全,则取出证书中的Mac公钥;
- 将取出的Mac公钥用于验证App的代码签名,如果验证没问题,再按照
mobileprovision
文件查看app所有权限和功能,如果everything ok,那么app就可以安装在真机上了。
九 iOS app从appStore下载的验证流程
从appStore下载验证流程就简单的多,通过pp助手等第三方工具下载一些线上的ipa文件,你会发现它里面没有
mobileprovision文件
。处理流程如下:1 当从appstore下载app,appStore会用apple私钥对app进行数字签名;
2 iOS设备拿到资源包后,会用本地apple公钥来验证数字签名是否正确,如果正确,则安装。
因为数据是来自于apple服务器,所以apple只需要保证app的完整性就好,防止中途被篡改。
签名小结
至此,我已经大致介绍了Xcode本地构建和iOS设备上的一些身份验证机制,其实整套流程就是对摘要算法和非对称加密的封装和应用。同时apple未来加强对于xcode本地构建项目的权限而设计了一个mobileprovision文件
的概念,这里只要区分好Hash摘要算法、非对称加密算法、数字签名、证书、描述文件等等概念,其实整套验证机制就不那么困难了,下次再遇到证书问题、签名问题,就不在需要不断google问别人怎么做的,直接对症下药了。
最后,为了更好的理解摘要算法和非对称加密算法,我再讲解一下HTTPS的实现原理。
十 加密算法在 HTTPS上的应用
HTTP是常见的应用层协议,是超文本传输协议的总称,其传输内容都是明文的,对此有一万种方式来劫持数据流,所以非常不安全。Https便应运而生,稍微牺牲一些速度而换取数据的传输安全,其中“s”表示SSL或TLS协议,就是在原有http的基础上加上一层数据加解密的安全层。
整个HTTPs的处理流程如下图:(PS画图不易哇!)
对照该流程图,我将分步详细说明:
- 对于一个服务器开发商而言,想要采用SSL/TSL协议,则必须先从CA机构获取证书。这需要先将服务器支持的
非对称加密的公钥
(本文简称Server公钥)和服务器运营商的注册信息等一起发给CA去审核; - CA审核通过后,会将Server公钥和网站注册信息以及一个CA的数字签名一同打包到数字证书中。其中数字签名是用CA私钥加密的,需要CA公钥来验证,而CA公钥是分发到各个操作系统中的;
- 当服务器有了数字证书,之后浏览器或者客户端在向该服务器的站点发送request,便可以将CA证书返回;
- 浏览器或者客户端向服务器站点发送request,需要先把其所支持的Hash算法、对称加密算法、非对称加密算法,以及浏览器的一些配置信息发送出去;
- 服务器在收到后,从这些算法中选择自己也支持的Hash、对称、非对称算法和CA数字证书一同发送给请求者;
- 客户端本地拿到CA证书之后,会用本地CA公钥先进行数字签名的验证,如果验证失败,则断开连接,否则取出CA证书中的
server公钥
; - 客户端生成一个随机的
key
,并且用server公钥
进行加密,生成一个key
的密文;然后用key
对本次握手进行Hash计算,并将计算结果用key
进行对称加密,生成一个握手消息的密文。最后将这两个密文一起发送给服务器; - 服务器拿到两个密文后,先用本地
server公钥
解密获取key
,然后用key
对握手消息密文解密拿到该hash值,并且自己也用相同摘要算法对握手消息进行hash计算,将两个hash值进行对比,如果不一致,则断开连接,否则用key
对称加密服务器端信息,然后发送给请求者。至此基于安全协议SSL的握手阶段结束,后续客户端和服务器都会用key
来对收发的消息进行对称加密解密。
上述过程属于单向认证的SSL协议的握手规则,但也有双向的认证的SSL协议的通讯,即要求服务器和用户双方都要有证书,双方都验证对方的证书的数字签名。
总结
- 本文主要先介绍了摘要算法、对称加密算法、非对称加密算法,在于此基础上讲解了何为数字签名、何为数字证书,以及两者的关联和作用;
- 接着本文家讲解了Xcode上打包ipa的处理流程,以及在真机上build的apple验证机制。同时也解释了appstore上下载app的验证流程;
- 最后未来更好了帮助大家理解这些加密算法的应用场景,例举了HTTPs的通讯原理。
希望本文对大家有所帮助,如果不当之处,还希望大家及时给我留言,共勉!