证书的申请流程
App Id 申请
一个 App Id 对应1个程序。在[iOS 开发者网站](https://developer.apple.com](https://link.jianshu.com/?t=https://developer.apple.com/) Certificates 中可以看到下图中的内容。点击 App IDs 中加号,填写 App ID,其中 Bundle ID 有 Explicit App ID 和 Wildcard App ID(通配符) 两种
证书申请
- 本地生成“证书请求文件” CSR 文件
- 钥匙串访问->证书助理->从证书颁发机构请求证书
- 选择“存储到磁盘” 即可生成一个 .certSigningRequest 文件
-
选择证书类型
- 上传之前本地生成的 CSR 文件,就生成了对应的证书文件 .cer。
授权文件申请 Provisioning Profile
-
选择授权文件类型
- 关联 App ID
- 选择关联的证书
- 选择授权的设备
iOS 代码签名
2008 年苹果发布 iOS 2.0时引入了强制代码签名(Mandatory Code Signing) 技术,为了能够严格控制设备上能够运行的代码,这为 iOS 设备的安全性和苹果的 AppStore 生态奠定了坚实的基础。
0x01 签名的作用
数字签名和手写签名类似,代表签名者对被签名数据的署名和认可,签名是对信息发送行为真实性的有效保障。iOS 代码签名的目的和好处如下
安全性
代码签名的首要任务是保证设备及系统的安全性,只有被苹果设备认可的证书签名的代码才能够被执行。iOS 系统内置了来自苹果的 CA 证书,系统自身的代码都是被苹果“签名”过的,而用户从 AppStore 下载的 App 也被苹果官方签名。签名机制可以有效防止来自外部的攻击,即能够避免非授权的恶意代码运行
沙盒
可以有效限制 App 的行为,这部分功能主要是由 Sandbox 机制来保证。但 Sandbox 的配置是绑定在签名中的,即 Entitlements 文件。如果 Entitlements 文件可以被任意修改,那么 Sandbox 就失去了意义。因此 Entitlements 文件也是强制签名保护的对象。
垄断
代码签名还给苹果带来了一个好处: App 分发的绝对控制权。
0x02 什么是签名
签名的本质是用于验证数据的合法性,确保被签名的数据来自特定的来源,并且未经篡改。它基于对称性加密和哈希算法。
公钥加密算法(非对称加密)
它在加密和解密时使用的是不同的密钥,具有这样的特征:
- 有一对密钥
a
和b
,满足a ≠ b
- 用密钥
a
加密的数据只能用b
进行解密,a
自身无法解密,反之亦然 - 只知道其中一个密钥,无法推导出另一个
-
把其中一个可以公开的叫做公钥,另一个不能公开的叫做似钥
最常见的公钥加密算法是 RSA 公钥加密算法,也是签名中普遍使用的算法
哈希算法
也叫散列或者摘要算法,对一段任意长度的数据,通过一定的映射和计算,得到一个固定长度的值,这个值就被称为这段数据的哈希值,给定一个哈希算法,它一定有如下特征:
- 哈希值不同的两段数据绝对不同
- 相同的数据计算出的哈希值绝对不同
- 由于哈希值是固定长度,也就意味着哈希值的数量是有限的。而任意数据都可以计算出一个哈希值,计算哈希的过程,相当于无限集映射到有限集。因此哈希值相同,对应的原始数据不一定相同,如果不同,则称这两段数据存在
哈希碰撞
,实际应用中任务是小概率事件,优秀的哈希算法都是碰撞率极低的。 - 哈希算法是单向算法,无法通过哈希值,计算出原始数据,这一点非常重要。
常见的哈希算法有:md5、sha1、sha256等,其中 sha1 长度为 160bits,而 sha256 长度为 256bits,二者相比,sha256 的取值范围更大,因此碰撞和破解的概率更低,也就相对安全
签名算法
有了上面两种算法作为基础,就可以组建一个签名和验证签名的体系了,如图所示
假如
A
要给 B
发送一段数据,先对其签名:
- 计算
d
的哈希值h
,并使用自己的私钥a
对h
进行加密,得到的密文c
就是签名。
得到签名后,将数据d
和签名c
通过某种方式发送给B
,此时B
收到了数据d’
以及签名c‘
,需要验证这段数据是否被篡改,以及是否是A
发送的 - 计算
d‘
的哈希值h’
,使用A
的公钥b
将签名c‘
解密,得到h’‘
,通过对比h’‘
和h’
是否一致,就可以知道数据的签名是否被篡改,如果哈希值是匹配的,能够说明这段数据一定是由A
签名并发出的。
常见的签名算法: - sha1WithRSAEncryption:先对数据计算 sha1 摘要,再对摘要进行 RSA 加密
- sha256WithRSAEncryption
- md5WithRSAEncryption
证书
上面例子中,任何需要接受 A
的消息的人都需要事先保存 A
的公钥。这样存在一个问题: B
不可能事先将所有来源的公钥提前保存。因此一般会把公钥当作签名的一部分岁数据一起分发,接收方不需要事先保存任何来源的公钥。
解决方案:可以把公钥和所有者信息保存在一个文件里,并让一个可信的第三者使用其私钥对这个文件进行签名,得到了一个签了名的公钥问价,这个文件叫做 证书
。证书会作为签名的一部分,随着数据一起分发。
此时我们还需要第三者的公钥验证这个证书的合法性。虽然需要多了验证第三者公钥这一步,但是这样,本地不再需要保存每个数据来源的公钥,只需要保存这个第三者的证书(公钥)即可,每个数据来源的证书都由这个可信的第三者进行签发,这个可信的第三者就被称为证书颁发机构(Certification Authority)简称 CA
0x03 开发者证书
iOS 设备并不能像 Android 那样任意安装 App,App 必须被 Apple 签名之后才能安装。而开发者开发 App 需要频繁修改代码,不可能每次都上传给 Apple 进行签名,因此需要一种不需要苹果签名就可以运行的机制。这个机制的实现方式是:
- 开发者自己持有一套密钥和证书,可以自行对 App 进行签名
- Apple 对开发者身份进行“背书”,让设备能够信任开发者自行签名的 App,这个“背书”方式的背后就是
Provisioning Profile
获取开发者证书的两个步骤:
生成 CSR 文件(Ceritificate Signing Request)
在 Keychain 菜单栏选择“从证书颁发机构请求证书”
这个操作会产生一个名为
CertificateSigningRequest.certSigningRequest
的签名请求文件,在生成这个文件之前,Keychain 已经自动生成了一对公、私钥CSR 文件的内容其实就是个人信息、公钥以及自签名(使用自己的私钥进行签名)。
提交给 Apple 进行签名
在苹果开发者网站,将 CSR 提交给 Apple 进行签名,Apple 会返回一个签好名的 证书文件
,后缀名为 cer
。双击将其导入 Keychain 中,Keychain 会自动把它与之前创建 CSR 时自动生成的密钥归为一组
可以得到几个关键信息:
- 证书所有者: Apple 根据我们的账号信息自动生成
- 证书的签发者:前文中的
CA
- 证书的公钥信息:与之前生成的密钥文件及 CSR 完全一致
现在应该可以理解证书与密钥的关系了,密钥中保存了私钥和公钥,私钥用于签名,而证书里面有且只有公钥,并且是被第三方 CA
认证公,用于解密和校验。
一般我们说使用 证书
签名,实际是使用与证书所匹配的私钥进行 签名
,证书
只是作为签名数据的一部分被嵌入到签名结构中。
开发证书、发布证书
开发者证书按用途分为 Development 证书和 Distribution 证书:
- Developent 证书:用于开发及测试阶段使用的证书,用于设备安装开发阶段的 App 后对 App 的完整性进行校验,一般名称为 iPhone Developer: xxxxxxx。如果是多人协作的开发者账号,任意成员都可申请自己的 Developent 证书
- Distribution 证书:用于提交 AppStore 的证书,一般命名为 iPhone Distribution: xxxxxxxxx,用于让 AppStore 校验提交的 App 的完整性,只有管理人员以上身份的开发者账号才可以申请,因此可以控制提交权限的范围,同时不能用于开发及调试。
0x04 Entitlements & Provisioning Profile
除了开发者证书,进行 iOS代码签名时还需要两个文件,它们是被签名内容的一部分
Entitlements
沙盒(Sandbox)技术时 iOS 安全体系中非常重要的一项技术,目的通过各种技术手段限制 App 的行为,比如可读写的路径、允许访问的硬件、允许使用的服务等,即使出现任意代码执行的漏洞,也无法影响到沙盒外的系统。
通常说的Entitlements 文件就是 iOS 沙盒的配置文件,这个文件声明了 app 所需的权限,如果 app 中使用了某项沙盒限制的功能,但是没有声明对应的权限,可能运行到相关的代码时会直接 crash
Provisioning Profile
Provisioning Profile 在这里签到了一个对设备和开发者授权的作用,它将开发者账号、证书、 entitlements 文件以及设备进行了绑定。
Xcode 8及后续版本默认情况下会自动帮我们管理 Provisioning Profile,自动下载的 Provisioning Profile 都被放在 ~/Library/MobileDevice/Provisioning\ Profiles/
路径下,以 UUID
格式命名。
由于这个文件时被苹果签过名的,所以我们没有办法伪造和修改这个文件。 Provisioning Profile 统一是由
Apple iPhone OS Provisioning Profile Signing
进行签名的,机构名称言简意赅。里面的内容关键的几项为:
- DeveloperCertificates: 允许使用的开发者证书,是一个列表,一般包含生成这个 Provisioning Profile 文件时当前开发者账号下所有有效的 Development 证书
- Entitlements:允许使用的权限列表,实际在 App 中使用的权限必须时这个列表的子集,否则安装时无法通过校验而失败
- ProvisionedDevices:允许安装的设备列表,如果目标设备的 UUID 不在这个列表中,会安装失败。
Provisioning Profile 会被内置在 App 中,置于App 根目录下的 embedded.mobileprovision
。安装 App 时如果签名校验通过,这个文件会自动被拷贝到 iOS 设备的 /Library/MobileDevice/Provisioning Profiles/
路径下。由于该文件已被 Apple 官方签名,系统可以无条件信任它,并用它来校验 App 的签名、权限以及本机的 UUID 等是否满足来自官方的授权,这种方式,间接信任了使用开发者证书签名的 App,让 App 设备可以运行非苹果官方签名的 App。
开发密钥 p12 文件
每一个证书都可以生成一个 .p12 文件,这是个加密文件,只要知道密码就可以供给其他 Mac 设备使用。使设备不需要在苹果开发者网站重新申请开发证书。
通过配置证书的电脑,在钥匙串访问中,右键证书->导出即可导出 p12 文件,安装到其他 Mac 上,其他 Mac 才可以使用 Provisioning Profi[图片上传中...(1178833-d16f85597dc10149.png-97ea38-1597921146793-0)]
le 副本
注意: .p12 文件一般是给别的电脑使用的
iOS 证书分类
账号分类
个人账号/公司账号:公司账号可以创建多个子账号,其它和个人账号没有区别
企业账号:企业开发者账号是不能发布 App 到 App Store 的,但苹果允许企业账号签名的 App 可以直接发布 App,无需经过苹果审核,签名后生成一个新的安装包,然后传到分发平台供所有iPhone 用户下载安装。这种发布方式,可以绕开目前苹果严苛的审核政策,不管是 App 的规模性测试,还是大规模的测试运营,都需要一个企业级开发者账号。
教育账号:只能是教育机构使用。必须是苹果 iOS 开发者计划授权机构。
证书分类
打包类型选择与分类
iOS App 打包最常用的是 Xcode 开发工具,在使用 Xcode 打包时,要想打不同类型的测试安装包,需要在 archive 阶段导包时选择不同的打包类型,下面是 4 种选项导出的包的含义:
Save for iOS App Store Deployment
准备上传 App Store 的 ipa 包,打包证书为公司账号或个人账号的发布证书。这个包也就是平时正常用户使用的线上包,所有在发布范围内的 iPhone 用户都可以使用。-
Save for Ad Hoc Deployment
苹果的官方解释是:To distribute your app to users with designated devices, select“Save for Ad Hoc Deployment.” The app will be code signed with the distributioncertificate.
根据官方文档说明,首先它是发布证书打包出来的,第一个选项 App Store 也是发布证书创建,只是第一个选项是发布到App Store,Ad Hoc是不能发布到App Store,这种包是平时测试中最常用的包,需要装的设备必须在开发者网站注册设备ID,最多100个。测试生产环境的推送选择该方式打包。
Save for Enterprise Deployment 生成企业包
企业版应用的ipa包,用于发布到自己服务器分发的应用,安装设备个数不受限制,也可直接发给你的客户或测试人员安装,无需在帐号中添加设备的udid。Save for Development Deployment
苹果的官方解释是:To distribute your app for internal testing, select “Save forDevelopment Deployment.” The app will be code signed with your developmentcertificate. (针对内部测试使用,主要给开发者的设备(具体也为在开发者账户下添加可用设备的udid),该 app 包是开发证书编译的)针对内部测试分发的 ipa 包,和 Ad Hoc 类似,都是测试用的,只不过这个选项的打包证书为开发证书。测试开发环境的推送选择该方式打包。