黑幕背后的 Code Signing

2018 年 8 月 27 日 CocoaChina
iOS 设备通常都会比 Android 设备更加安全,这得益于 Apple 拥有自己完整的生态 —— AppStore。所有应用发布以及所有的 iOS 设备(越狱的除外)下载软件都要经由 Apple 进行验证,而工作在背后的正是   Code Signing  


作为一个 iOSer 可能在处理证书问题的时候(尤其是多人协作),看到 Keychain、Certificates、Private Key、AppID、Provisioning Profile、CertificateSigningRequest、entitlements 以及 P12等一堆概念简直头都要秃了。 

本文从原理入手,从为什么有这些概念入手,对 App Signing 原理进行一遍梳理,再来探究怎么做才是最佳实践,来为大家揭开黑幕背后的 Code Signing

为什么?

使用惯了 Windows PC 以及 安卓手机的朋友可能已经习惯了随便哪里都能下载到软件,甚至于去下载破解亦或是盗版软件,这也对直接导致了系统性的风险,成为一些别有用心人士的肉鸡。在 AppStore 诞生的时候,Apple 试图去解决这些问题,来对 iOS 以及运行于之上的第三方 Apps 有绝对的掌控权,来保证用户手机上的每一个 App 都是经过认证的、安全的。那么怎么做呢?没错,苹果发明了一套签名机制,在 Mac OS X Leopard 10.5 (也是第一台 iPhone 发布的时候)上首次运用了这项技术。

一些概念

非对称加密

公开密钥加密(英语:Public-key cryptography),也称为非对称加密(英语:asymmetric cryptography),是密码学的一中演算法,它需要两個密钥,一個是公开密钥,另一個是私有密钥;一個用作加密的時候,另一個則用作解密。使用其中一個密钥把明文加密后所得的密文,只能用相对应的另一個密钥才能解密得到原本的明文;甚至连最初用來加密的密钥也不能用作解密。由于加密和解密需要兩個不同的密钥,故被称为非对称加密;不同于加密和解密都使用同一個密钥的对称加密。(引用自维基百科)。

数字签名

我们已经大致了解了非对称加密的概念,那么什么是数字签名呢?数字签名就是类似于物理签名,但是使用了公钥加密领域的技术实现,用于鉴别数字信息的方法。一套数字签名通常定义了两种互补的算法,一个用来签名,一个用来验证。数字签名了的文件的完整性是很容易验证的,而且数字签名具有不可抵赖性。

一言以蔽之,数字签名就是将公钥密码反过来使用。签名者把数据(通常是散列值)用私钥加密,用公钥将加密的数据解密并比对。

Keychain Access

Keychain Access 是 macOS 中保存用户账户密码的工具,用户的公钥以及私钥也都被 keychain 管理着。我们可以使用 keychain 的证书助手来申请公私钥。生成的 CertificateSigningRequest 就是公钥,私钥保存在 keychain 中。

AppID、Provisioning Profile、entitlements 以及 p12

AppID 是由 TeamID 和 BundleID 组合而成,类似于 A1B2C3D4.com.domain.appName形式。分为 Wildcard App ID 和 Explicit App ID,前者适用于一组 Apps,后者只是用于单个 App。

Entitlements 包含了 App 关于 iCloud、Push、backgroundMode 等权限信息。

Provisioning Profile 里边包含了数字签名信息、授权设备列表信息、Entitlements 等信息以及这些信息的签名。
p12 是一种文件格式,里边包含了我们的私钥信息以及符合 X.509 标准的公钥。

Apple 的 code signing 工具是如何工作的?

前边我们提到了数字签名的过程,只需要一对公私钥就可以实现如下图的签名流程

可是为什么在 Apple 的体系中又多了上述那么多额外的概念?这是因为我们从 App Store 下载应用的时候,上述的数字签名过程虽然可以满足我们的需求,但是对于 iOS 应用来说,在开发阶段我们还可以借助 Xcode 来把应用安装在我们的手机上,还可以使用 In-House 以及 Ad-hoc 形式来安装我们的应用。这就产生了新的问题:

1) IPA 文件不用经过苹果的服务器,就能经过认真安装到我们的手机上。
2) 苹果对应用掌握绝对的主动权:
3) 只有经过苹果允许才能安装;
4) 避免开发阶段的 app 被安装在任意手机。

为了实现解决这些问题,苹果的工程师使用了双层签名,大致流程如下:

  • 在你的 Mac 开发机器生成一对公私钥,这里称为公钥L,私钥L。L:Local 苹果自己有固定的一对公私钥,跟上面 AppStore 例子一样,私钥在苹果后台,公钥在每个 iOS 设备上。这里称为公钥A,私钥A。A:Apple

  • 把公钥 L 传到苹果后台,用苹果后台里的私钥 A 去签名公钥 L。得到一份数据包含了公钥 L 以及其签名,把这份数据称为证书。

  • 在苹果后台申请 AppID,配置好设备 ID 列表和 APP 可使用的权限,再加上第③步的证书,组成的数据用私钥 A 签名,把数据和签名一起组成一个 Provisioning Profile 文件,下载到本地 Mac 开发机。

  • 在开发时,编译完一个 APP 后,用本地的私钥 L 对这个 APP 进行签名,同时把第④步得到的 Provisioning Profile 文件打包进 APP 里,文件名为 embedded.mobileprovision,把 APP 安装到手机上。

  • 在安装时,iOS 系统取得证书,通过系统内置的公钥 A,去验证 embedded.mobileprovision 的数字签名是否正确,里面的证书签名也会再验一遍。

  • 确保了 embedded.mobileprovision 里的数据都是苹果授权以后,就可以取出里面的数据,做各种验证,包括用公钥 L 验证APP签名,验证设备 ID 是否在 ID 列表上,AppID 是否对应得上,权限开关是否跟 APP 里的 Entitlements 对应等。

如何做?

  • 第 1 步对应的是 keychain 里的 “从证书颁发机构请求证书”,这里就本地生成了一对公私钥,保存的 CertificateSigningRequest 就是公钥,私钥保存在本地电脑里。

  • 第 2 步苹果处理,不用管。

  • 第 3 步对应把 CertificateSigningRequest 传到苹果后台生成证书,并下载到本地。这时本地有两个证书,一个是第 1 步生成的,一个是这里下载回来的,keychain 会把这两个证书关联起来,因为他们公私钥是对应的,在XCode选择下载回来的证书时,实际上会找到 keychain 里对应的私钥去签名。这里私钥只有生成它的这台 Mac 有,如果别的 Mac 也要编译签名这个 App 怎么办?答案是把私钥导出给其他 Mac 用,在 keychain 里导出私钥,就会存成 .p12 文件,其他 Mac 打开后就导入了这个私钥。

  • 第 4 步都是在苹果网站上操作,配置 AppID / 权限 / 设备等,最后下载 Provisioning Profile 文件。

  • 第 5 步 XCode 会通过第 3 步下载回来的证书(存着公钥),在本地找到对应的私钥(第一步生成的),用本地私钥去签名 App,并把 Provisioning Profile 文件命名为 embedded.mobileprovision 一起打包进去。这里对 App 的签名数据保存分两部分,Mach-O 可执行文件会把签名直接写入这个文件里,其他资源文件则会保存在 _CodeSignature 目录下。


但是显然这么做对于我们来说还是不太方便。在 Xcode8 中,苹果加入了自动管理机制,可以参考 WWDC 2016 - Session 401。但是对于我来说这还是不够好用,下一节我将来告诉大家我是如何使用 Fastlane Certmatch 以及sign 工具来管理我的证书。

END -

登录查看更多
0

相关内容

Mac PC 和 macOS 的使用技巧
【干货书】现代数据平台架构,636页pdf
专知会员服务
257+阅读 · 2020年6月15日
最新《自动微分手册》77页pdf
专知会员服务
102+阅读 · 2020年6月6日
【实用书】Python技术手册,第三版767页pdf
专知会员服务
238+阅读 · 2020年5月21日
干净的数据:数据清洗入门与实践,204页pdf
专知会员服务
164+阅读 · 2020年5月14日
【实用书】Python爬虫Web抓取数据,第二版,306页pdf
专知会员服务
122+阅读 · 2020年5月10日
斯坦福2020硬课《分布式算法与优化》
专知会员服务
122+阅读 · 2020年5月6日
【资源】100+本免费数据科学书
专知会员服务
108+阅读 · 2020年3月17日
【2020新书】Kafka实战:Kafka in Action,209页pdf
专知会员服务
69+阅读 · 2020年3月9日
算法与数据结构Python,369页pdf
专知会员服务
165+阅读 · 2020年3月4日
【电子书】C++ Primer Plus 第6版,附PDF
专知会员服务
88+阅读 · 2019年11月25日
3 行代码 5 秒抠图的 AI 神器,根本无需 PS
大数据技术
20+阅读 · 2019年7月24日
被动DNS,一个被忽视的安全利器
运维帮
11+阅读 · 2019年3月8日
R_leaflet包_最易上手地图教程(一)
R语言中文社区
10+阅读 · 2019年3月6日
吃鸡手游竟然是Python写的?
机器学习算法与Python学习
7+阅读 · 2018年9月11日
我是一个爬虫
码农翻身
12+阅读 · 2018年6月4日
Python为啥这么牛?
Python程序员
3+阅读 · 2018年3月30日
号称“开发者神器”的GitHub,到底该怎么用?
算法与数据结构
4+阅读 · 2018年3月29日
Kaggle入门手册
Datartisan数据工匠
14+阅读 · 2017年11月9日
相似图片搜索的原理
数据库开发
9+阅读 · 2017年8月11日
33款可用来抓数据的开源爬虫软件工具 (推荐收藏)
数据科学浅谈
7+阅读 · 2017年7月29日
Arxiv
9+阅读 · 2018年10月24日
VIP会员
相关VIP内容
【干货书】现代数据平台架构,636页pdf
专知会员服务
257+阅读 · 2020年6月15日
最新《自动微分手册》77页pdf
专知会员服务
102+阅读 · 2020年6月6日
【实用书】Python技术手册,第三版767页pdf
专知会员服务
238+阅读 · 2020年5月21日
干净的数据:数据清洗入门与实践,204页pdf
专知会员服务
164+阅读 · 2020年5月14日
【实用书】Python爬虫Web抓取数据,第二版,306页pdf
专知会员服务
122+阅读 · 2020年5月10日
斯坦福2020硬课《分布式算法与优化》
专知会员服务
122+阅读 · 2020年5月6日
【资源】100+本免费数据科学书
专知会员服务
108+阅读 · 2020年3月17日
【2020新书】Kafka实战:Kafka in Action,209页pdf
专知会员服务
69+阅读 · 2020年3月9日
算法与数据结构Python,369页pdf
专知会员服务
165+阅读 · 2020年3月4日
【电子书】C++ Primer Plus 第6版,附PDF
专知会员服务
88+阅读 · 2019年11月25日
相关资讯
3 行代码 5 秒抠图的 AI 神器,根本无需 PS
大数据技术
20+阅读 · 2019年7月24日
被动DNS,一个被忽视的安全利器
运维帮
11+阅读 · 2019年3月8日
R_leaflet包_最易上手地图教程(一)
R语言中文社区
10+阅读 · 2019年3月6日
吃鸡手游竟然是Python写的?
机器学习算法与Python学习
7+阅读 · 2018年9月11日
我是一个爬虫
码农翻身
12+阅读 · 2018年6月4日
Python为啥这么牛?
Python程序员
3+阅读 · 2018年3月30日
号称“开发者神器”的GitHub,到底该怎么用?
算法与数据结构
4+阅读 · 2018年3月29日
Kaggle入门手册
Datartisan数据工匠
14+阅读 · 2017年11月9日
相似图片搜索的原理
数据库开发
9+阅读 · 2017年8月11日
33款可用来抓数据的开源爬虫软件工具 (推荐收藏)
数据科学浅谈
7+阅读 · 2017年7月29日
Top
微信扫码咨询专知VIP会员