iOS之APP签名的双向验证机制和原理
非对称加密
- 通常我们说的签名就是数字签名,它是基于非对称加密算法实现的。
- 对称加密是通过同一份**加密和解密数据,而非对称加密则有两份**,分别是公钥和私钥,用公钥加密的数据,要用私钥才能解密,用私钥加密的数据,要用公钥才能解密。
- 非对称加密算法 RSA 的数学原理:
① 选两个质数 p 和 q,相乘得出一个大整数n,例如p = 61,q = 53,n = pq = 3233;
② 选 1-n 间的随便一个质数e,例如 e = 17;
③ 经过一系列数学公式,算出一个数字 d(通过RSA 算法得出),满足:
a.通过 n 和 e 这两个数据一组数据进行数学运算后,可以通过 n 和 d 去反解运算,反过来也可以;
b.如果只知道 n 和 e,要推导出 d,需要知道 p 和 q,也就是要需要把 n 因数分解; - 上述的 (n,e) 这两个数据在一起就是公钥,(n,d) 这两个数据就是私钥,满足用私钥加密,公钥解密,或反过来公钥加密,私钥解密,也满足在只暴露公钥 (只知道 n 和 e)的情况下,要推导出私钥 (n,d),需要把大整数 n 因数分解。
- 目前因数分解只能靠暴力穷举,而 n 数字越大,越难以用穷举计算出因数 p 和 q,也就越安全,当 n 大到二进制 1024 位或 2048 位时,以目前技术要**几乎不可能,所以非常安全。
- RSA加密的常用方式:公钥加密,私钥解密;私钥签名,公钥验签。
代码签名
- 在iOS出来之前,以前的主流操作系统(Mac/Windows)软件随便从哪里下载都能运行,系统安全存在隐患,盗版软件、病毒入侵、静默安装等等。那么苹果希望解决这样的问题,要保证每一个安装到 iOS 上的 APP 都是经过苹果官方允许的,怎样保证呢?就是通过代码签名。
- 如果要实现验证,其实最简单的方式:就是通过苹果官方生成非对称加密的一对公私钥。在iOS的系统中内置一个公钥,私钥由苹果后台保存,我们传APP到AppStore时,苹果后台用私钥对APP数据进行签名,iOS系统下载这个APP后,用公钥验证这个签名,若签名正确,这个APP肯定是由苹果后台认证的,并且没有被修改过,也就达到了苹果的需求:保证安装的每一个APP都是经过苹果官方允许的。
- 如果iOS设备安装APP只从App Store这一个入口这件事就简单解决了,没有任何复杂的东西,一个数字签名搞定。但是实际上iOS安装APP还有其他渠道,比如对于开发者iOSER而言,是需要在开发APP时直接真机调试的。而且苹果还开放了企业内部分发的渠道,企业证书签名的APP也是需要顺利安装的。
- 苹果需要开放这些方式安装APP,这些需求就无法通过简单的代码签名来办到了。
双向签名
苹果需求
- 安装包不需要上传到App Store,可以直接安装到手机上;
- 苹果为了保证系统的安全性,又必须对安装的APP有绝对的控制权:
① 经过苹果允许才可以安装;
② 不能被滥用导致非开发APP也能被安装;
双向签名的原理
这里有两个角色:一个是iOS系统,还有一个就是Mac系统,因为iOS的APP开发环境在Mac系统下,所以这个依赖关系成为了苹果双层签名的基础。
- 在Mac系统里面使用软件Xcode生成一对非对称的加密算法的公钥和私钥;公钥M包含在CSR文件中,私钥M也就是P12文件保存MAC电脑的keychain中;
- 苹果服务器也会生成一对固定的公钥和私钥,跟之前App Store原理一样,私钥在苹果的后台,公钥在我们的iOS设备上这里称为公钥A , 私钥A(A=Apple);
- 将Mac的公钥M包装成CSR文件传到苹果后台之后(通过CSR文件请求证书),苹果会用私钥A对CSR文件进行签名,也就是私钥A对公钥M的hash值签名生成证书,经过苹果私钥A加密后,证书再绑定appID及测试开发设备列表,就生成了provisioning profile描述文件,返回给Mac设备;
- 在开发时,编译完一个 APP 后,将会使用到本地的苹果企业开发者证书私钥 M(也即为P12文件)来给APP进行签名,并将上面得到的证书一块打包到APP里面,安装到手机,进行真机调试或者提交审核;
- 在APP进行安装的时候,iOS系统需要取得内置公钥来去检测私钥的数字签名的证书是不是正确(iPhone的公钥A可以解析APP里面的证书);
- 验证完成以后就表明APP的安装时被允许的(也即为钥M是苹果认证过的),认证结束就可以保证开发者以及程序的安全;
- iOS上的公钥A把provisioning profile文件解密了,就验证了这个APP是经过苹果官方认证的,同时也得到了测试设备和CSR请求中的公钥A。再用公钥 M 去验证 APP 的签名,这里就间接验证了这个 APP 安装行为是否经过苹果官方允许。(这里只验证安装行为,不验证APP 是否被改动,因为开发阶段 APP 内容总是不断变化的,苹果不需要管。)
描述文件
什么是描述文件?
- 有了上面的过程,已经可以保证开发者的认证和程序的安全性了。 但是,你要知道iOS的程序,主要渠道是要通过APP Store才能分发到用户设备的,如果只有上述的过程,那岂不是只要申请了一个证书,就可以安装到所有iOS设备了?怎么才能解决“不能被滥用导致非开发APP也能被安装”的问题呢?
- 苹果为了解决应用滥用的问题,所以又加了两个限制:
① 第一限制在苹果后台注册过的设备才可以安装;
② 第二限制签名只能针对某一个具体的APP。 - 在申请证书之后想要成功的真机调试,还有一个重要步骤,就是分别配置开发模式、发布模式的描述文件吧"XXX.mobileprovision"。必须要在描述文件内部指定设备号,才能调试对应的APP;
- 苹果是怎样操作的呢?可以想到苹果把允许安装的设备 ID 列表 和 App 对应的 AppID 等数据,都在上面的“双向签名”的第三步“私钥A对CSR文件进行签名”这里,跟公钥 M 一起组成证书,再用苹果私钥 A 对这个证书签名。在最后“内置公钥来去检测私钥的数字签名的证书”这一步验证时,就可以拿到设备 ID 列表,判断当前设备是否符合要求。根据数字签名的原理,只要数字签名通过验证,这里的设备 IDs / AppID / 公钥 M 就都是经过苹果认证的,无法被修改,苹果就可以限制可安装的设备和 App,避免滥用。
- 苹果还想控制App里面的iCloud/PUSH/后台运行/调试器附加这些权限,所以苹果把这些权限开关统一称为Entitlements(授权文件),并将这个文件放在了一个叫做Provisioning Profile(描述文件)文件中;
- 描述文件是在AppleDevelop网站创建的(在Xcode中填上AppleID它会代办创建),Xcode运行时会打包进入APP内。所以使用CSR申请证书时,我们还要申请一个东西, 这就是描述文件。
- 在开发时,编译完一个 APP 后,用本地的私钥M对这个APP进行签名,同时把从苹果服务器得到的 Provisioning Profile 文件打包进APP里,文件名为embedded.mobileprovision,把 APP 安装到手机上,最后系统进行验证。
描述文件的信息
- 描述文件(Provisioning profile)一般包括三样东西:证书、App ID、设备。当我们在真机运行或者打包一个项目的时候,证书用来证明我们程序的安全性和合法性。
- 描述文件的路径
- 打开终端,输入命令(security cms -Di )+ 描述文件名,就可以查看对应描述文件的全部详情信息(即为plist文件);
- 可将信息全部复制到Xcode工程的plist文件中直观查看: