导读:iOS 签名校验机制是苹果生态平安的根底,日常工作中无论是开发阶段还是测试阶段经常会遇到很多须要通过签名机制解决的问题,理解 iOS 签名机制的原理有助于进步咱们解决相干问题的老本和效率。本文首先介绍数字签名和证书的原理,之后会介绍苹果开发者证书的生成装置过程,最初对苹果实现签名校验的流程及流程中波及的要害信息进行介绍,心愿能对大家有所帮忙。
全文 9494 字,预计浏览工夫 24 分钟。
背景
iOS15 beta 版公布后,QA 同学须要测试新性能在 iOS 15 零碎下的性能稳定性,然而通过公司流水线打出的企业包无奈装置在 iOS 15 零碎的设施上,具体报错见下图:
通过在控制台查看装置过程中的具体报错信息,发现具体的 IPA 包的签名信息在 iOS 15 零碎上曾经不再被反对了:The code signature version is no longer supported. 具体的控制台报错信息如下图所示:
也就是装置失败和 IPA 的代码签名版本无关,为此通过 codesign 命令查看流水线产出的 IPA 的相干签名信息,具体信息见下图,其中 CodeDirectory 的版本为 v =20400:
CodeDirectory 直译是代码目录,记录的是将 Mach- O 文件分页后每页的哈希值信息,除此之外还蕴含了资源文件的摘要信息、权限信息等,这些信息依照肯定的格局组合在一起,而不同的 signature version 对应这不同的信息品种、组合模式或计算算法。去年从 iOS 14 beta2 开始,苹果零碎采纳一种更为平安的签名格局,在其上运行应用旧签名格局签名的 APP 时会出正告弹窗。其官网介绍中提到 In a future release, the new format will become mandatory, and the system won’t launch apps with the old signature format. 因而狐疑是签名格局在 iOS 15 零碎上进行了强制校验,导致装置失败:
在官网文档中提到 If you signed your app on a Mac running macOS 10.14 or later, the app already has the new signature format. 换句话说 macOS 零碎的版本会影响到签名的格局;“For any value of v less than 20400, you’ll need to re-sign your app.”
当 CodeDirectory version 的值小于 20400 时能够通过重签名来解决签名生效问题。而 CodeDirectory v=20400 能够装置在 iOS 14 零碎上,然而却无奈装置在 iOS 15 零碎上。为了解决这个问题,采纳重签名的思路,在 macOS 11.5.2 及 macOS 12.0 Beta 版零碎下别离对流水线 IPA 包重签名后,均能够失常装置在 iOS 15 零碎上了。
以上是 iOS 签名校验机制的一个体现,日常开发及测试中,与上述 iOS 签名校验机制相干的事件还有很多比方批改零碎工夫后使得企业证书过期从而导致启动解体等,在这里再和大家一起分享下无关 iOS 证书与签名校验相干的一些信息。
首先咱们看几个问题:
- 什么是签名校验机制?
对可执行文件或脚本进行数字签名,用来保障软件在签名后未被侵害或者批改的措施;
- 苹果为什么要应用签名校验机制?
Signing your app allows iOS to identify who signed your app and to verify that your app hasn’t been modified since you signed it.
即确定 APP 起源并避免内部攻打,以实现苹果对其生态的管制;
- 苹果如何实现签名校验?
这是 iOS 签名校验机制的流程示意图,在学习过程中,集体感觉了解分明非对称加密、数字签名以及数字证书的原理对于了解整个签名机制十分重要,因而在文章的开始会对加密与解密、数字签名以及数字证书做一些阐明,而后联合数字签名和证书的原理,对苹果创立开发者证书的流程以及 iOS 签名校验流程包含过程中波及到一些要害信息进行阐明:
- 加密与解密、数字签名、证书在通信过程中各自的作用
- 解析苹果开发者证书的生成装置过程
- 苹果实现签名校验的流程及要害信息
一、加密与解密、数字签名、证书在通信过程中各自的作用
无论是从 AppStore 下载 App 装置到手机上还是在 Debug 阶段通过 Xcode 将 App 装置到测试机上进行真机调试,其实都是一次将 App 包发送到手机沙盒中的一次通信过程,如何保障一次平安无效的通信呢?或者说在一次通信过程中可能面临哪些平安问题呢?
A 向 B 发送的明文,能够被两头路由间接查看,泄密了 — 被窃听
好事者 C 批改了 A 向 B 申请内容,使得 A 发动了谬误申请 — 被篡改
好事者 C 拦挡并模仿 A 向 B 发动申请,让 B 误以为是 A 发动的 — 被坑骗
A 向 B 发动了申请,然而 A 就是不抵赖发动了此次申请 — 被否定
1.1 避免被窃听 – 加密与解密
通信过程中是不好防止被第三方拦挡的,然而咱们能够做到即使被截获,窃听者依然无奈破译无效的信息,这个过程能够通过加密来实现。
目前加密算法次要有两大类,对称加密和非对称加密:
对称加密的特点是加密和解密应用的同一个秘钥,其特点是速度快,罕用算法有:DES、3DES、AES;
非对称加密的密钥分为公钥和私钥,其最重要的个性是应用公钥加密的信息,只能应用私钥解密,而应用私钥加密的信息,只能应用公钥进行解密,最罕用的算法有 RSA;
然而对称加密的密钥治理繁琐且密钥传输存在肯定的安全隐患,而非对称加密算法速度比较慢,尤其是对于加密数据较大的信息时耗时更加显著。因而在理论应用过程中,最常应用的是混合加密形式:
发送方:1. 对信息 (明文) 采纳 DES 密钥加密;2. 应用 RSA 加密后面的 DES 密钥信息;而后将 1 和 2 步产生的信息进行整合后传递。
接管方:接管到信息后:1. 用 RSA 解密 DES 密钥信息;2. 再用 RSA 解密获取到的密钥信息解密密文信息;最终就能够失去咱们要的信息(明文)。
1.3 避免否定 – 数字签名
因为公钥是对外公开的,A 能够应用公钥加密信息计算摘要,B 也能够应用公钥加密信息计算摘要,也就是所有领有公钥的人都可能成为信息发送者,这就导致 A 发送音讯后能够否定。后面咱们有提到非对称加密的个性:应用公钥加密的信息,只能应用私钥解密,而应用私钥加密的信息,只能应用公钥进行解密。公钥是对外公开的,然而私钥仅存在于密钥对生成者本人手里,所以当在发送音讯时应用发送者的私钥加密信息,在接收端应用发送者的公钥来解密信息,那么接收端就能够准确确认音讯发送者了,也就解决了音讯发送者否定发送的问题。应用发送者的私钥对摘要进行加密,就造成了签名,即数字签名。
咱们来看下数字签名是如何起作用的:
总结下数字签名的作用,次要有三点:1. 能够确认音讯的完整性;2. 能够辨认音讯是否被篡改;3. 能够避免音讯发送者否定;
然而咱们不能漠视一点:数字签名失效的前提:用于加密的公钥必须属于真正的接受者,用于解密的公钥必须属于真正的发送者。如果公钥被伪造了或者说好事者假冒发送者去发送音讯,单纯依赖数字签名是无奈解决的;咱们一起来看下公钥被伪造时会产生什么:
由上图能够看到,如果公钥在传输过程中被伪造了,那么后续相干的通信过程都是建设一个伪造的密钥对间进行,从而导致这个通信过程不再平安。因而在验证签名之前,首先得先验证公钥的合法性。
然而如何保障公钥的合法性呢?
依据下面的相干介绍,为了保障公钥信息不被篡改和坑骗,那么最好的形式就是对公钥进行数字签名,但问题又来了,如何保障此次数字签名验证过程中公钥的合法性呢?再来一次数字签名吗?这就陷入了一个鸡生蛋蛋生鸡的过程了,为了突破这个死循环,人们发明了证书核心和数字证书。
1.4. 保障公钥的合法性 – 数字证书
循环进行数字签名的起因是因为公钥有可能被伪造,为此人们将一些具备公信力的组织或者政府部门作为证书核心,由证书核心应用本人的私钥来对公钥进行数字签名。艰深了解证书核心就是那些可能认定“公钥的确属于此人”并且可能生成数字签名的权威集体或者组织,简称 CA。而由 CA 对公钥等信息施加数字签名后就生成了证书。
咱们一起看下数字证书是如何起作用的:
音讯接收者首先生成密钥对,并将公钥_B 及邮箱等信息在 CA 认证机构中进行注册,认证机构 CA 用本人的私钥_CA 对公钥_B 进行数字签名,并生成证书;音讯发送者 A 向认证机构 CA 申请证书,并通过认证机构 CA 的公钥_CA 验证数字签名,以验证公钥_B 的合法性。
对此,咱们对公钥、私钥、数字签名、数字证书的概念及作用有了一个大略的回顾。上面咱们从数字签名及数字证书的生成流程角度来看下 iOS 开发者证书的生成与装置过程。
二、苹果开发者证书的生成与装置
-1. 生成证书申请:钥匙串拜访 -> 证书助理 -> 从证书颁发机构申请证书(能够了解为 Mac 端创立非对称加密密钥对公钥 M 和 私钥 M 的过程,应用私钥 M 来签订生成 CSR 文件,CSR 文件中蕴含开发者的信息和公钥 M,私钥 M 则存储在 Mac 端本地)
-2. 登录开发者平台,将第一步生成的 CertificateSigningRequest.certSigningRequest 上传至 Developer 生成证书。(CertificateSigningRequest.certSigningRequest 能够了解为 Mac 生成的公钥,上传至开发者平台能够为将公钥 M 在证书认证机构 CA 进行注册,并利用苹果开发者核心的公钥 A 对 Mac 设施的公钥进行签名,生成开发者证书)
- 3.Mac 将证书下载到本地,双击装置(在装置过程中,钥匙串 keychain 会将第一步生成的私钥 M 与第二步生成的 Cer 证书关联在一起:
三、苹果实现签名校验的流程及要害信息
苹果签名校验机制的作用是要保障每一个装置到 iOS 设施上的 App 都是通过苹果官网受权的。为了实现上述成果,苹果采取的计划是双重签名,其大略流程能够参见下图:
1. 首先在 Mac 端生成一对密钥对(公钥 M 和私钥 M),苹果也会生成一对秘钥对(公钥 A 和私钥 A),其中公钥 A 预置在 iOS 设施上,私钥 A 放在苹果服务器中;
2. 开发者通过开发者后盾将公钥 M 上传至苹果服务器,苹果服务器应用私钥 A 对公钥 M 进行签名生成证书,开发者下载该证书并装置在 Mac 中。装置过程中会将证书与私钥 M 进行关联。
3. 在开发过程中,会应用私钥 M 对 APP 进行签名,同时会将证书也打包进 APP 中。
4. 在装置过程中,iOS 零碎首先会应用预置的公钥 A 对证书进行验证,失去公钥 M(验证胜利,即阐明证书是通过苹果私钥签名过的,依据后面的解说咱们晓得这样就阐明是通过苹果认证的了),而后应用公钥 M 对签名进行验证,验证胜利后能力将 APP 装置在设施中。
那是不是只有领有一个通过苹果认证的开发者证书,就能够将任意 App 装置在任意测试机上呢?显然这是苹果生态所不容许的。那苹果是通过什么形式实现设施限度的呢?而且,在团队开发中,也并不是所有人都去生成开发者证书,那又是通过什么形式实现团队受权的呢?以及在苹果开发者核心中配置的 BundleID、Capabilities、Devices 等信息在签名机制中又扮演着什么样的作用呢?
3.1 对于 P12 – 团队合作开发
在下面的签名过程中,咱们看到开发者在对 App 进行签名过程中,次要用到两个信息:私钥 M 和证书,因而只须要将这两个信息提供给团队中的其它成员。在证书装置过程咱们理解中,钥匙串会将证书与 Mac 生成的私钥 M 进行关联并存储为钥匙串中的一项,钥匙串反对将其导出为 p12 文件,而后咱们将 p12 文件提供给团队成员装置就能够了。
3.2 对于 Entitlements – 权限管控
Xcode 在编译打包时会主动执行 /usr/bin/codesign 命令进行代码签名,以下是签名的详细信息:
在签名时通过 –sign 指定了证书信息,那么 –entitlements 配置的是什么信息呢?
entitlements 链接:
(https://developer.apple.com/l…)
An Entitlement can be thought of as the string written into an app’s signature that allows a specific capability or opts the app into a specific service. The operating system (OS) checks these strings before allowing an app access to certain features. For example, an app must have the iCloud entitlement before it is allowed to access iCloud APIs at runtime.
简略来说 entitlements 其实就是 iOS 沙盒环境的配置文件,苹果通过 entitlements 文件来管控一个 App 所能应用的服务和权限。Sandbox(沙盒)是 iOS 平安体系中很重要的一环,沙盒不仅仅使 App 间互相独立,同时也对每个 App 可操作的行为进行了管控,比方能够应用哪些敏感的零碎能力(Push、Sign in with apple 等)等。Xcode 会默认生成一个蕴含有 Team ID 信息和 App ID 信息的权限申明,如果在 Xcode Signing&Capabilities 中开启了相干权限,那么会显式的生成一个后缀名为.entitlements 的配置文件,外面蕴含了相干权限信息的阐明。在 –entitlements 选项前面的文件是在.entitlements 的配置文件根底上减少了默认配置后的信息。在 Xcode 签名时,会将该权限信息文件嵌入到二进制代码中,作为被签名内容的一部分,由代码签名保障其不会被篡改。
可通过 security cms -D -i /path/to/iOSTest.mobileprovision 来查看本地的 Provisioning Profile 是否蕴含所须要的权限。
3.3 对于 Provisioning profile
Provisioning profile act as a link between the device and the developer account. During development, you choose which devices can run your app and which app services your app can access. A provisioning profile is downloaded from your developer account and embedded in the app bundle, and the entire bundle is code-signed.
Provisioning Profile 是一个由苹果证书核心加密签名的一个 plist 文件,蕴含有与之绑定的 App ID、设施的 UUID 列表、过期工夫、TeamID、entilements 等信息以及用于对应用程序进行签名的证书,是苹果用来解决对设施受权以及管控 APP 敏感权限的解决方案。其在证书核心的配置页面如下:
在证书核心配置完 App ID、Unique Device Identifiers 以及 capabilities 等信息后,苹果证书核心会将这些信息与证书一起应用苹果的私钥进行签名,最初将签名信息与配置信息、证书、签名信息一起组成一个 Provisioning Profile 文件。开发者将其下载并装置,默认状况下 Xcode 会主动帮忙开发者进行治理。以下是 Xcode 中装置的 Provisioning Profile 信息:
在 Mac 编译完一个 App 后,会将 Provisioning Profile 文件也打包进 App 中,并将文件命名为 embedded.mobileprovision。在 App 装置到 iOS 设施上时,iOS 设施会通过预置的公钥信息来验证 embedded.mobileprovision 的签名合法性,进而验证证书中的签名是否正确。
确保了 embedded.mobileprovision 里的数据都是苹果受权当前,就能够应用其中的信息来校验本次装置的合法性,应用公钥 A 验证 Mach-O 的签名信息、验证证书的签名及有效期、验证设施 ID 是否在设施列表中、Provisioning Profile 中的 App ID 是否与 BundleID 是否匹配等等;
值得注意的一点是:设施列表只在 Development 证书下失效,因为 Enterprise、Distribution 证书自身就是要求能够任意装置,所以不受设施列表的限度;过期工夫只对 Development、Enterprise 证书失效,Distribution 证书下不受限制,这也是当 Development、Enterprise 证书过期后会导致利用无奈装置或无奈启动,而从 App Store 下载的利用不会有工夫限度。
当然在开发者核心能够随时对 Provisioning Profile 进行批改,更新不会对已有 Provisioning Profile 产生影响。
3.4 对于可执行文件与资源的签名
在编译生成 App 的过程中,Xcode 会通过钥匙串找到与配置证书配对的私钥 M 对二进制文件进行签名,并将签名信息嵌入到可执行二进制文件中,用于在装置时确认 Mach-O 文件是否有被批改。可通过 MackOView 验证:
然而 App 中不仅仅蕴含二进制文件,还蕴含一系列诸如图片、音视频文件等预置资源,因而通过繁多的对二进制文件进行签名不足以保障整个 App 文件的完整性和有效性。在 iOS 中,应用程序应用遵循 shallow application bundles 构造的目录来存储必要资源和数据信息,大抵为:
TestProject.app | 用户可见应用程序
Info.plist | 文件,其中蕴含无关软件包的信息
TestProject | 可执行二进制
Assets.car | 图标,显示为用户可见应用程序
Framework | 任何可执行文件应用的框架或动静库
AFNetworking.framework |iOS 软件中常见框架示例
以下是一个非常简单的 IPA 包的包构造:
能够看到为了保障可执行文件及其在运行期间所依赖的数据和资源不被篡改,在理论生成的 APP 包中,会新生成一个_CodeSignature 目录,在该目录下蕴含一个名为 CodeResources 文件,该文件为 plist 类型的文件,外面蕴含了 App 下除可执行文件外其它文件的信息,key 通常为文件名,value 通常为其摘要信息。外面会有 files 和 files2 两项,其中 files 保留的是每个文件的 sha1 的值,files2 同时保留了 sha1 和 sha256,次要起因是 sha1 存在不安全性。_CodeSignature/CodeResources 文件的次要作用是记录签名后每个文件的哈希值,以在装置时用来确保对应的文件没有被篡改过。
3.5 签名及校验流程
1. 首先在 Mac 端生成一对密钥对(公钥 M 和私钥 M),苹果零碎自身也会生成一对密钥对(公钥 A 和私钥 A),其中公钥 A 预置在 iOS 设施上,私钥 A 放在苹果服务器中;
2. 开发者将公钥 M 整合在 csr 文件中通过开发者后盾上传至苹果服务器,苹果服务器应用私钥 A 对公钥 M 进行数字签名生成证书;同时应用私钥 A 将证书、AppID、entilements、设施 UDIDs 等信息加密生成 Provisioning Profile 文件;对应的开发者下载证书和 Provisioning Profile 文件并装置在 Mac 中。装置过程中会将证书与私钥 M 进行关联,Xcode 默认会对 Provisioning Profile 文件进行治理。
3. 在开发过程中,会应用私钥 M 对 App 进行签名,同时会将 Provisioning Profile 文件也打包进 App 中即 embedded.mobileprovision 文件。
4. 当将 iOS 设施与 Xcode 连贯并通过身份验证后,Xcode 会将 App 数据传输到 iOS 设施中,iOS 设施此时并不会创立真正的沙盒环境来运行 App,而是会在一个长期沙盒环境中来寄存陆续收到的数据,一旦全副接管完,iOS 零碎首先会应用预置的公钥 A 对 embedded.mobileprovision 文件的签名进行验证,已确认 App 起源是否非法;起源合法性验证通过后,便可应用公钥 M 去验证外面证书的签名信息、验证该设施 ID 是否在对应 UUID 列表中、以及 APP 中的权限开关配置是否和 embedded.mobileprovision 文件中配置的 entilements 信息相吻合等;同时会读取_CodeSignature/CodeResources 中的信息对资源文件进行校验。只有全副通过验证后,才会为 App 创立真正的沙盒环境进行装置。在启动 APP 时,零碎也会执行相应的启动校验,以避免装置后进行的批改。
参考文献:
1.https://developer.apple.com/d…
2.https://developer.apple.com/l…
3.https://pewpewthespells.com/b…
4.http://blog.cnbang.net/tech/3…
5.https://developer.apple.com/l…
6.https://developer.apple.com/l…
7.https://developer.apple.com/l…
8.https://getupdraft.com/blog/i…
9.https://abhimuralidharan.medi…
点击进入取得更多技术信息~~