2

iOS | 图解iOS签名背后的原理

 1 year ago
source link: https://mp.weixin.qq.com/s?__biz=Mzg3MjcxNzUxOQ%3D%3D&mid=2247484901&idx=1&sn=83fcf34b5b4b7a63c17742efa3ee20a8&chksm=ceea4845f99dc1537003bdebd2a93d09c9b413ad0cc8c5108cd93d5b84e63e65a30ce0f6c019&token=996185752&lang=zh_CN
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

iOS | 图解iOS签名背后的原理点击上方"Bo2SS"关注"星标"置顶不迷路

图片

上周我给组里做了一次“学习汇报”,其实也是组里每周都有的技术分享,每个人都有机会,这次轮到我了。那作为团队菜鸟,我该讲点什么呢?

我思前想后,突然想到自己之前老是遇到的一个棘手的问题:在真机上运行iOS工程时,工程还没跑起来,工程配置的签名(Targets > Signing & Capabilities)那里就先报错了,不管是自己的工程,第三方开源库,还是公司的项目。

虽然自己每次面向谷歌或者面向同事都可以找到答案,但为什么能解决以及为什么真机运行iOS项目需要签名,自己只能说是对它们一知半解、被它们弄得云里雾里。

不过现在我总算明白了它们背后的奥秘!如果你也有同样的困惑,往下看,保证这次让你彻底弄懂它——iOS签名背后的原理

阅读完本文会让你拥有轻松解决以下问题的能力:

  1. 如何在真机上跑自己的iOS项目,或者iOS开源库?
  2. 如何在真机上跑公司的iOS项目?

另外,本文的终极目标是:遇到任何iOS签名相关问题时,你都能够快速解决。

预备知识:数字签名 & 数字证书

在聊iOS签名之前,我们先需要了解两个预备知识,那就是在互联网世界里的签名✒️和证书📄。

可参考:数字签名和数字证书是什么?[1]——阮一峰

数字签名一般夹带在要传输的数据中,用来防止数据被篡改。

它的底层核心是哈希混淆算法非对称加密技术(公/私钥)。

签名Signature的生成由通信中的发送方Sender进行,首先对要传输的数据Data进行哈希Hash混淆得到数据摘要Digest,然后用私钥Private Key对摘要进行加密,这样就生成了数据的签名。

图片

接收方Receiver接收来自发送方的数据和签名,对它们分别做如下处理:

  • 数据:使用与发送方相同的哈希算法对数据进行混淆,得到数据摘要A;
  • 签名:利用发送方加密所用私钥对应的公钥Public Key,对签名进行解密,得到数据摘要B。

比对摘要A和摘要B,如果相等,则说明数据没有被篡改,否则数据存在问题。

图片

签名的生成和验证过程合在一起如下图所示,自己再分析一遍可加深理解。

图片

带着问题往下走

Q1: 猜想一下iOS签名和验签的过程,App开发者和App使用者中,谁是发送方,谁是接收方,传输的数据又是什么呢?

A1: App开发者是发送方,App使用者是接收方,传输的数据就是App的安装包。

Q2: 接收方如何拿到解密所用的公钥呢?

请接着往下看。

在了解数字证书之前,我们可能马上想到的是,发送方在发送数据和签名的同时,再附带上公钥不就万事俱备了吗~如下图所示:

图片

但是这样会引入一个新的问题

Q1: 接收方如何确认公钥没有被其他人恶意替换呢?也就是公钥的身份不明。

这时候数字证书就该登场了。

我们可以先看一下数字证书的组成内容,它由公钥、公钥的身份信息Identity Info以及它们的签名B组成。

图片

注意:加密公钥数据所用的私钥又是另外一个公私钥组合了,它是由权威的认证机构(Certificate Authority,CA)颁发的。

公钥包装在数字证书中传递

这下,原来发送方发送的内容由数据+签名+公钥,变成了数据+签名+证书

图片

证书里包含了接收方解密签名A所需的公钥,除此之外,证书里还有公钥的身份信息和签名B:

  1. 身份信息的存在则可以消除公钥身份不明的隐患;
  2. 签名B则对公钥及其身份信息未被篡改做了保证

但也因为有了签名B,我们在取公钥时,还需要先对证书里的签名B进行验证:

图片

注意:解密证书里签名B所用的公钥也是由CA颁发的,它存在于CA证书里。

现在,我猜你已经能够记住证书的组成内容了:公钥+公钥的身份信息+它们的签名。

带着问题往下走

Q1: 接收方从哪里获得这个CA证书呢?接收方又要如何验证这个CA证书的签名呢?似乎进入了无限循环♻️。

请接着往下看。

证书信任链

CA证书一般是在安装系统/软件时内置的,这样我们总该信任它了吧~

接下来,我们可以再了解一下证书的信任链。

根据证书在信任链中所处的位置,可以将证书分为三种

  • 根证书Root Certificate(参考Apple 操作系统中可用的受信任根证书[2]——Apple官方)
  • 中间证书Intermediate Certificate
  • 叶子证书Leaf Certificate

举例:我的开发者证书A(Apple Development)由中间证书B(Apple Worldwide Developer Relations Certification Authority,安装Xcode时内置)的CA签发,中间证书B由根证书C(Apple Root CA,系统内置)的CA签发,而根证书C是由自己的CA签发的,因为C已经在信任链的顶端啦,它自己说了算。

图片

回到上一个问题:如何保证这个CA证书可信呢?只要接收方有签发方的证书,那么用证书里的公钥验证一下就可以了。比如一台iPhone安装我开发的App时,收到了我的开发者证书A,那么手机就会去找签发方的证书B(Apple Worldwide Developer Relations Certification Authority,iOS系统内置)来验证A是否可信。

现在,你也可以看看自己的Mac > 钥匙串Keychain软件 > 证书Certificates,加深理解。

继续带着问题往下走

Q1: 加密公钥及其身份信息所用的CA私钥在我们的电脑本地吗?如果不是,该如何生成我们的证书呢?

iOS证书申请原理 & 申请方法

当然不是,这些私钥可是CA签发证书的秘密宝贝。比如,我们要想申请iOS开发者证书,则需要找Apple官方帮忙,Apple官方会使用上面提到的中间证书CA的私钥来签发证书。

想要申请自己的iOS开发者证书,分为以下几步:

  1. 用自己的电脑生成公私钥对,并填写公私钥对的身份信息;
  2. 将公钥及其身份信息发送给Apple CA;
  3. CA使用使用哈希算法和CA私钥对数据(公钥及其身份信息)进行签名,数据和签名则组成了我们想要的证书;
  4. 我们再在CA上把证书下载到电脑上,安装证书后电脑会自动关联对应的私钥。
图片

申请方式:2种

具体的申请方式有2种:1)上传CSR (CSR, Certificate Signing Request) 文件方式,2)Xcode自动申请方式,这里推荐第二种。

1)上传CSR文件方式

该方法适合想了解iOS证书申请原理的你。注意:该方式需要加入苹果开发者计划[3],$99/年。

a) 打开Keychain > Certificate Assistant > Request a Certificate From a Certificate Authority...:

图片

b) 输入身份信息(邮箱、证书名字),可以选择保存到本地,本地就得到了一个CSR (.certSigningRequest) 文件,里面包含了公钥及其身份信息。

图片

你可能会问,那私钥放在哪里呢?如果你细心的话,你会发现Keychain > login > Keys里面已经多了一对你命名的公私钥对。

c) 登陆Apple Developer[4]网站,进入Certificates, Identifiers & Profiles板块,上传刚刚生成的CSR文件,即可生成证书(.cer文件),此时将证书下载到本地,双击即可导入Keychain,在Keychain > login > May Certificates中可以看到该证书。

图片

如果你细心的话,你会发现Keychain里该证书已经和一把私钥绑定起来了,如果想把证书共享给其它开发者使用,则需要右键导出我们熟悉的.p12文件,它包含了证书和对应的私钥~

2)Xcode自动申请方式(推荐)

这种方式则不需要繁琐的上传CSR文件、下载.cer证书过程,也不会强求你加入Apple开发者计划。

a) 在Xcode里登陆Apple账号:Xcode > Preference > Account > Apple IDs > 「+」。

图片

b) 登陆片刻后,你就会发现KeyChain里自动多出一份相应的证书了。

图片

注意:如果你加入了开发者计划,Apple开发者网站上也会自动添加该证书。

iOS签名 & 打包原理

终于来到iOS签名部分了,前面的内容你理解的怎么样呢?如果你还有点迷糊,那么记住签名的作用是防止传输的数据被篡改这一点,你就基本掌握本文的真谛了!

其实,在真正iOS签名的时候,还不是只附加证书(含公钥)这一个东西,我们还需要对证书做一层包装,那就是我们熟悉的Provisioning Profile文件,又叫PP文件、描述文件、供应配置文件。

先来了解一下这个重要的PP文件,我们可以把它理解为证书的升级版。

  1. 开发者平台上申请;
  2. Xcode自动生成:Xcode > Targets > Signing & Capabilities > 勾选Automatically manage signing。
图片
  • App ID:
    • 在Apple开发者平台上注册;或者根据Xcode > Targets > Signing & Capabilities填写的Bundle ID自动生成。
    • 我们在Xcode > Targets > Signing & Capabilities中填写的Bunlde Identifier必须与App ID是一致或匹配的。
  • Entitlements:
    • 允许使用的权限列表,实际在App中使用的权限必须是这个列表的子集,即我们在Xcode > Targets > Signing & Capabilities中添加的Capabilities,不能超出其范围。
    • 工程目录下也会有一份.entitlements文件(授权文件),它是根据Xcode > Targets > Signing & Capabilities里添加的Capabilities自动生成的。如果 App 中使用到了某项沙盒限制的功能,但是该.entitlements文件没有声明对应的权限,当App运行到相关代码时,App会直接 Crash。
  • Certificates:由iOS开发者证书组成,可以不只一个,它们就是上面申请到的iOS证书。
  • Devices:由iOS设备的UDID (Unique Device Identifier) 组成的列表,限定了可以开发调试该App的iOS设备。
  • Signature:在生成PP文件时,由Apple CA对其进行签名,防止被人篡改。

PP文件默认保存在:~/Library/MobileDevice/Provisioning\ Profiles

下面是Xcode自动生成的一个PP文件预览:

图片

签名 & 打包

iOS签名和打包过程其实是由Xcode来把控的,看下图:

图片
  1. 首先,Xcode会检查App里的bundle ID是否匹配PP文件中的App ID,以及App里的Entitlements (.entitlements) 文件声明的权限是否在PP文件中Entitlements允许权限的范围内,二者任一条件为否,则检查不通过;
  2. 其次,Xcode会在电脑的Keychain里找,是否有匹配PP文件中Certificates的证书,如果匹配到了,才继续下一步;
  3. 然后,Xcode会检查匹配到的证书是否绑定了对应的私钥,如果没有,就无法进行下面的关键步骤——签名;
  4. 现在,开始利用哈希算法和私钥对App进行签名了;
  5. 最终,对App、PP文件和签名进行打包,即生成.ipa包。

⚠️:上面忽略了签名C和签名A的验证过程,在第1步使用PP文件之前和在第2步匹配到证书之后,都应先使用CA公钥对其附带的签名C和A进行验证,防止它们被篡改。如有错误,欢迎指正。

延伸问题

Q1: Xcode会对App的哪些内容进行签名呢?

A1: 全部内容。但签名过程较为复杂,这里就不展开了,简而言之,为了权衡签名的安全性和效率,App的签名被分为4次哈希和1次加密,每次哈希都是环环相扣的,保证了App内容没有被篡改。

图片

具体可参考细说iOS代码签名(三):签名的过程及代码签名的数据结构[5]。

iOS验签原理

说完了iOS签名,那真机在安装App时如何验证它的签名呢?

首先,我们需要知道的是,App安装包分为测试包正式包,两者的验签过程有所不同。

顺便补充一下测试包和正式包的知识:

1)测试包:分为内测包、准备上传App Store的发布包、Ad Hoc发布包、In-house企业内部发布包4种类型。

2)正式包:上传到App Store上的安装包。

⚠️:Xcode打的包都属于测试包。

参考iOS不同类型测试包介绍——搜狗测试公众号。

安装测试包时,真机对其进行了完整的验签过程,如下图所示:

图片
  1. 首先,真机设备会使用系统内置的CA公钥验证PP文件及其签名C的合法性;
  2. 其次,真机再使用系统内置的CA公钥验证PP文件中证书及其签名A的合法性;(App里保存了生成签名B所用的证书信息,这样真机才知道去取出哪个证书里的公钥)
  3. 然后,真机再取出证书中的公钥验证App及其签名B的合法性;
  4. 最后,真机会检查自己的UDID是否在PP文件的Devices列表中,如果存在,才开始安装App。

⚠️:图里简化了验签的过程,相信你已经很熟悉这个过程了,哈希混淆、公钥解密、判等...

其实,签名的验证并非一次性完成,在安装、启动和运行时有着不同的校验规则,上面简化了该过程,具体可参考细说iOS代码签名(四):签名校验、越狱、重签名[6]。

而安装正式包时,真机对其的验签过程简化了很多,因为对开发者证书的验签过程交给了App Store

1)将发布包上传到App Store。

图片
  1. 当你将发布包(测试包的一种)上传到App Store时,Apple官方同样会对发布包进行验签,其过程类似上述测试包的验签过程;
  2. 验签通过后,App Store会重新对App进行签名,这里用的就不是开发者证书对应的私钥了,而是CA 私钥;
  3. 最后,App Store只会对App和新的签名进行打包,生成.ipa包。(⚠️:不包含PP文件了)

2)真机设备安装正式包。

图片

当设备从 App Store上下载 App 后,只需要用系统内置的CA公钥对App进行验签,验证通过即可安装。

网上也有一些画得很好的图,你们可以按照序号回顾一遍过程,用来巩固本文的内容。

图片

来自iOS证书那些事儿[7]——掘金。

图片

来自iOS App 签名的原理[8]——Blog。

回到:本文目标

最后,我们再回到文章开头目标里提出的问题,解决那些问题之前永远铭记两个东西:包含私钥的证书(.p12 = .cer + private key)、PP文件(.mobileprovision)。

再看看我们的问题,只要找到上面两个东西就可以了:

  1. 如何在真机上跑自己的iOS项目,或者iOS开源库?
    1. 包含私钥的证书:参考iOS证书申请方式那一节;
    2. PP文件:在开发者平台上申请;或者由Xcode自动生成,Targets > Signing & Capabilities > 勾选Automatically manage signing。
  2. 如何在真机上跑公司的iOS项目?
    1. 包含私钥的证书:向团队索要,注意文件后缀是.p12;
    2. PP文件:向团队索要,记得让负责人在开发者平台上添加自己真机的UDID到PP文件中。
  • 运行测试包安装的App时,一般还需要在真机上信任证书:Settings > General > VPN & Device Management。
  • Xcode自动生成PP文件:
图片

整体把握:iOS 证书幕后原理[9]——Blog

深度理解:细说iOS代码签名[10]——Blog

其它你可能感兴趣的:

  • iOS证书和描述文件申请[11]——DClound
  • iOS 应用的发布方式有哪些[12]?——知乎
  • iOS重签名探索[13]——简书

[1]

数字签名和数字证书是什么?: https://www.ruanyifeng.com/blog/2011/08/what_is_a_digital_signature.html

[2]

Apple 操作系统中可用的受信任根证书: https://support.apple.com/zh-cn/HT209143

[3]

加入苹果开发者计划: https://developer.apple.com/account

[4]

Apple Developer: https://developer.apple.com/account

[5]

细说iOS代码签名(三):签名的过程及代码签名的数据结构: http://xelz.info/blog/2019/01/11/ios-code-signature-3/http://xelz.info/blog/2019/01/11/ios-code-signature-3/

[6]

细说iOS代码签名(四):签名校验、越狱、重签名: http://xelz.info/blog/2019/01/11/ios-code-signature-4/

[7]

iOS证书那些事儿: https://juejin.cn/post/6949731496211152903

[8]

iOS App 签名的原理: http://blog.cnbang.net/tech/3386/

[9]

iOS 证书幕后原理: http://chuquan.me/2020/03/22/ios-certificate-principle/

[10]

细说iOS代码签名: http://xelz.info/blog/2019/01/11/ios-code-signature-1/

[11]

iOS证书和描述文件申请: https://ask.dcloud.net.cn/article/152

[12]

iOS 应用的发布方式有哪些: https://www.zhihu.com/question/19998722

[13]

iOS重签名探索: https://www.jianshu.com/p/6b659c669338


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK