热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

iosAPP签名

前言相信很多同学对于iOS的真机调试,App的打包发布等过程中的各种证书、ProvisioningProfile、 CertificateSigningRequest、p12的概念

前言

相信很多同学对于iOS的真机调试,App的打包发布等过程中的各种证书、Provisioning Profile、 CertificateSigningRequestp12的概念是模糊的,导致在实际操作过程中也很容易出错。好在Xcode8.0出现了Automatically manage signing,让我们在这步操作中减少了难度。虽然说我们在Xcode8.0之后可以选择让Xcode自动管理了,但是我们还是应该知道App签名的原理。本文尝试从原理出发,一步步推出为什么会有这么多概念,希望能有助于理解iOS App签名的原理和流程。

签名目的

先来看看苹果采用签名机制的目的。在iOS出来之前,在主流操作系统(Mac/Windows/Linux)上开发和运行软件是不需要签名的,软件随便从哪里下载都能运行,导致平台对第三方软件难以控制,盗版流行。苹果就希望在iOS平台对第三方App有绝对的控制权,一定要保证每一个安装到iOS上的App都必须经过苹果官方认证的。那么问题来了,怎么保证呢?就是通过签名这种机制。

非对称加密

通常我们所说的签名就是数字签名,它是基于非对称加密算法实现的。对称加密是通过同一份密钥加密和解密数据,而非对称加密则有两份密钥,分别是公钥和私钥,用公钥加密的数据,要用私钥才能解密;用私钥加密的数据,要用公钥才能解密。

简单说一下常用的非对称加密算法RSA的数学原理,理解简单的数学原理,就可以理解非对称加密是怎么做到的,为什么是安全的:

1. 选两个质数`p`和`q`,相乘得出一个大整数`n`,例如:p=61,q=53,n=p*q=3233
2. 选 1-`n` 间的随便一个质数`e`,例如:e=17
3. 经过一系列数学公式,算出一个数字`d`,满足:
    a. 通过`n`和`e`这两个数据进行数学运算后,可以通过`n`和`d`去反解运算,反过来也可以。
    b. 如果只知道`n`和`e`,要推导出`d`,需要知道`p`和`q`,也就是需要把`n`因数分解。
    

上述的(n,e)这两个数据在一起就是公钥,(n,d)这两个数据就是私钥,满足用公钥加密,私钥解密,或者反过来私钥加密,公钥解密;也满足在只暴露公钥(只知道ne)的情况下,要推导出私钥(n,d)需要把大整数n因数分解,目前因数分解只能靠暴力穷举,而n数字越大,越难以用穷举计算出因数pq,也就越安全,当n大到二进制1024位或2048位时,以目前技术要破解几乎不可能,所以非常安全。

若对数字d是怎样计算出来的感兴趣,可以详读这两篇文章:RSA 算法原理(一)(二)

数字签名

现在知道了有非对称加密算法这东西,那么数字签名是怎么回事呢?
数字签名的作用是我对某一份数据打了个标记,表示我认可了这份数据(签了个名),然后我发送给其他人,其他人可以知道这份数据是经过我认证的,数据没有被篡改过。
有了上述非对称加密,就可以实现这个需求:
技术分享图片

  1. 首先用一种算法,算出原始数据的摘要,需要满足:

    a. 若原始数据有任何变化,计算出来的摘要值也要有变化。

    b. 摘要要够短,这里常用的算法是MD5

  2. 生成一份非对称加密的公钥和私钥,私钥自己拿着,公钥发布出去。
  3. 对一份数据,算出摘要之后,用私钥加密这个摘要,得到一份加密后的数据,称为原始数据的签名。把它跟原始数据一起发送给用户。
  4. 用户收到数据和签名后,用公钥解密得到摘要,同时用户用同样的算法计算原始数据的摘要,比对这里计算出来的摘要和公钥解密签名得到的摘要是否相等,若相等则表示这份数据中途没有被篡改过,因为如果有篡改,摘要会变化。

之所以要有第一步计算摘要,是因为非对称加密的原理限制可加密的内容不能太大(不能大于上述n的位数,也就是一般不能大于1024位/2048位),于是若要对任意大的数据签名,就需要改成对它的特征值签名,效果是一样的。

好了,有了非对称加密和数字签名的基础之后,怎么样可以保证一份数据是经过某个地方认证的,来看看怎么样通过数字签名的机制来保证每一个安装到iOS的App都是经过苹果认证允许的。

最简单的签名

要实现这个需求很简单,最直接的方式,苹果官方生成一对公私钥,在iOS里内置一个公钥,私钥由苹果后台保存,我们传App上AppStore时,苹果后台用私钥对App数据进行签名,iOS系统下载这个App后,用公钥验证这个签名,若签名正确,这个App肯定由苹果后台认证的,并且没有被修改过,也就达到了苹果的需求:保证安装的每一个App都是经过苹果认证允许的。
技术分享图片

如果我们iOS安装App只有从AppStore下载一种方式的话,这样就可以搞定了,没有任何复杂的东西,只有一个数字签名,非常简单的解决问题。
但是实际上,因为安装App除了从AppStore下载,我们还可以有三种方式安装一个App:

  1. 开发App时可以直接把开发中的应用安装进手机调试;
  2. In-House企业内部分发,可以直接安装企业证书签名后的App;
  3. AD-Hoc相当于企业分发的限制版,限制安装设备数量,较少用。

苹果要对用这三种方式安装的App进行控制,就有了新的需求,无法像上面这件简单了。

新的需求

我们先来看第一个,开发时安装App,它有两个需求:

  1. 安装包不需要传到苹果服务器,可以直接安装到手机上。如果你编译一个App到手机前要先传到苹果服务器签名,这显然是不能接受的。
  2. 苹果必须对这里的安装有控制权,包括:

    a. 经过苹果允许才可以这样安装;

    b. 不能被滥用导致非开发App也能这样安装;

为了实现这些需求,iOS签名的复杂度也就开始增加了。
苹果这里给出的方案是使用了双层签名,会比较绕,流程大概是这样的:
技术分享图片

  1. 在你的Mac开发机器生成一对公私钥,这里称公钥L,私钥L。(L:Local)
  2. 苹果自己有固定的一对公私钥,跟上面AppStore例子一样,私钥在苹果后台,公钥内置在每个iOS设备上,这里称为公钥A,私钥A。(A:Apple)
  3. 把公钥L上传到苹果后台,用苹果后台里的私钥A去签名公钥L。得到一份数据包含了公钥L以及其签名,把这份数据称为证书。
  4. 在开发时,编译完一个App后,用本地的私钥L对这个App进行签名,同时把第三步得到的证书一起打包进App里,安装到手机。
  5. 在安装时,iOS系统取得证书,通过系统内置的公钥A,去验证证书的数字签名是否正确。
  6. 验证证书确保公钥L是苹果认证过的,再用公钥L去验证App的签名,这里就间接验证了这个App的安装行为是否经过苹果官方允许。(这里只验证安装行为,不验证App是否被改动,因为开发阶段App内容总是不断变化的,苹果不需要管)。

加点东西

上述流程只解决了上面第一个需求,也就是需要经过苹果允许才可以安装,还未解决第二个避免被滥用的问题。怎么解决呢?苹果加了两个限制,一是限制在苹果后台注册过的设备才可以安装;二是限制签名只能针对某一个具体的App。
那么它到底是怎么添加这两个限制的呢?在上述第三步,苹果用私钥A签名我们的本地公钥L时,实际上除了签名本地公钥L外,还可以加上无限多数据,这些数据都可以保证是经过苹果官方认证的,不会有被篡改的可能。
技术分享图片

可以想到把允许安装的设备ID列表和App对应的AppID等数据,都在第三步这里跟公钥L一起组成证书,再用苹果私钥A对这个证书签名。在最后第5步验证时就可以拿到设备ID列表,判断当前设备是否符合要求。根据数字签名的原理,只要数字签名通过验证,第5步这里的设备IDs/AppID/公钥L就都是经过苹果认证的,无法被修改,苹果就可以限制可安装的设备和APP,避免滥用。

最终流程

到这里这个证书已经变得很复杂了,有很多额外信息,实际上除了设备ID/AppID,还有其他信息也需要在这里用苹果签名,像App里iCloudpush、后台运行 等权限苹果都想控制,苹果把这些权限开关统称为Entitlements,它也需要通过签名去授权。
实际上一个证书本来就有规定的格式规范,上面我们把各种额外的信息塞入证书里是不合适的,于是苹果另外搞了一个东西,叫Provisioning Profile,一个Provisioning Profile里就包含了证书以及上述提到的所有额外信息,以及所有信息的签名。
所以,整个流程稍微变一下,就成这样了:
技术分享图片

因为步骤有小变动,这里我们不辞啰嗦重新再列一遍整个流程:

  1. 在你的 Mac 开发机器生成一对公私钥,这里称为公钥L,私钥L。L:Local
  2. 苹果自己有固定的一对公私钥,跟上面 AppStore 例子一样,私钥在苹果后台,公钥在每个iOS设备上。这里称为公钥A,私钥A。A:Apple
  3. 把公钥L传到苹果后台,用苹果后台里的私钥A去签名公钥L。得到一份数据包含了公钥L以及其签名,把这份数据称为证书。
  4. 在苹果后台申请AppID,配置好设备ID列表和APP可使用的权限,再加上第③步的证书,组成的数据用私钥A签名,把数据和签名一起组成一个Provisioning Profile文件,下载到本地Mac开发机。
  5. 在开发时,编译完一个APP后,用本地的私钥L对这个APP进行签名,同时把第④步得到的Provisioning Profile文件打包进APP里,文件名为 embedded.mobileprovision,把APP安装到手机上。
  6. 在安装时,iOS系统取得证书,通过系统内置的公钥A,去验证 embedded.mobileprovision的数字签名是否正确,里面的证书签名也会再验一遍。
  7. 确保了embedded.mobileprovision里的数据都是苹果授权以后,就可以取出里面的数据,做各种验证,包括用公钥L验证APP签名,验证设备ID是否在ID列表上,AppID是否对应得上,权限开关是否跟APP里的Entitlements对应等。

开发者证书从签名到认证最终苹果采用的流程大致是这样,还有一些细节像证书有效期/证书类型等就不细说了。

概念和实际操作

上面的步骤对应到我们平常具体的操作和概念是这样的:

  1. 第1步对应的是keychain里的“从证书颁发机构请求证书”,这里就本地生成了一对公私钥,保存的CertificateSigningRequest就是公钥,私钥保存在本地电脑里。
  2. 第2步苹果自己处理,我们不用管。
  3. 第3步对应把CertificateSigningRequest传到苹果后台生成证书,并下载到本地。这时本地有两个证书,一个是第1步生成的,一个是这里下载回来的,keychain会把这两个证书关联起来,因为它们的公私钥是对应的,在Xcode选择下载回来的证书的时,实际上会找到keychain里面对应的私钥去签名。这里私钥只有生成它的这台Mac才有,如果别的Mac也要编译签名这个App,怎么办?答案是把私钥导出给其他Mac使用,在keychain里面导出私钥,就会存成.p12文件,其他Mac打开后就导入私钥。
  4. 第4步都是在苹果网站上操作,配置AppID权限设备等,最后下载 Provisioning Profile文件。
  5. 第5步Xcode会通过第3步下载回来的证书(存着本地公钥),在本地找到对应的私钥(第1步生成的),用本地私钥去签名App,并把Provisioning Profile文件命名为embedded.mobileprovision一起打包进去。这里对App的签名数据保存分为两部分,Mach-O可执行文件会把签名直接写入这个文件里,其他资源文件则会保存在_CodeSignature目录下。
  6. 第6、7步的打包和验证都是 Xcode 和 iOS 系统自动做的事。

这里再总结一下这些概念:
证书:内容是公钥或私钥,由其他机构对其签名组成的数据包。
Entitlements:包含了App权限开关列表。
CertificateSigningRequest:本地公钥。
.p12:本地私钥,可以导入到其他电脑。
Provisioning Profile:包含了 证书/Entitlements 等数据,并由苹果后台私钥签名的数据包。

其他发布方式

前面以开发包为例子说了签名和验证的流程,另外两种方式In-House企业签名和AD-Hoc流程也是差不多的,只是企业签名不限制安装的设备数,另外需要用户在iOS系统设置上手动点击信任这个企业才能通过验证。
AppStore的签名验证方式有些不一样,前面我们说到最简单的签名方式,苹果在后台直接用私钥签名App就可以了,实际上苹果确实是这样做的,如果去下载一个AppStore的安装包,会发现它里面是没有embedded.mobileprovision文件的,也就是它安装和启动的流程是不依赖这个文件,验证流程也就跟上述几种类型不一样了。

据猜测,因为上传到AppStore的包苹果会重新对内容加密,原来的本地私钥签名就没有用了,需要重新签名,从AppStore下载的包苹果也并不打算控制它的有效期,不需要内置一个embedded.mobileprovision去做校验,直接在苹果用后台的私钥重新签名,iOS安装时用本地公钥验证App签名就可以了。

那为什么发布AppStore的包还是要跟开发版一样搞各种证书和Provisioning Profile?猜测因为苹果想做统一管理,Provisioning Profile里包含一些权限控制,AppID 的检验等,苹果不想在上传AppStore 包时重新用另一种协议做一遍这些验证,就不如统一把这部分放在 Provisioning Profile里,上传AppStore时只要用同样的流程验证这个 Provisioning Profile是否合法就可以了。

所以 App 上传到AppStore后,就跟你的 证书 / Provisioning Profile 都没有关系了,无论他们是否过期或被废除,都不会影响AppStore 上的安装包。

到这里 iOS 签名机制的原理和主流程大致说完了,希望能对理解苹果签名和排查日常签名问题有所帮助。

致谢

感谢各位能改耐心看完,也希望能够对大家带来帮助。同时也感谢原作者的文章。本篇文章主要是为了做笔记。

最后,打一波广告,需要签名的朋友可以加QQ:2302398895 一朋友专业做ios APP签名。

ios APP 签名


推荐阅读
  • 《数据结构》学习笔记3——串匹配算法性能评估
    本文主要讨论串匹配算法的性能评估,包括模式匹配、字符种类数量、算法复杂度等内容。通过借助C++中的头文件和库,可以实现对串的匹配操作。其中蛮力算法的复杂度为O(m*n),通过随机取出长度为m的子串作为模式P,在文本T中进行匹配,统计平均复杂度。对于成功和失败的匹配分别进行测试,分析其平均复杂度。详情请参考相关学习资源。 ... [详细]
  • HDU 2372 El Dorado(DP)的最长上升子序列长度求解方法
    本文介绍了解决HDU 2372 El Dorado问题的一种动态规划方法,通过循环k的方式求解最长上升子序列的长度。具体实现过程包括初始化dp数组、读取数列、计算最长上升子序列长度等步骤。 ... [详细]
  • 本文介绍了OC学习笔记中的@property和@synthesize,包括属性的定义和合成的使用方法。通过示例代码详细讲解了@property和@synthesize的作用和用法。 ... [详细]
  • 动态规划算法的基本步骤及最长递增子序列问题详解
    本文详细介绍了动态规划算法的基本步骤,包括划分阶段、选择状态、决策和状态转移方程,并以最长递增子序列问题为例进行了详细解析。动态规划算法的有效性依赖于问题本身所具有的最优子结构性质和子问题重叠性质。通过将子问题的解保存在一个表中,在以后尽可能多地利用这些子问题的解,从而提高算法的效率。 ... [详细]
  • 高质量SQL书写的30条建议
    本文提供了30条关于优化SQL的建议,包括避免使用select *,使用具体字段,以及使用limit 1等。这些建议是基于实际开发经验总结出来的,旨在帮助读者优化SQL查询。 ... [详细]
  • 本文介绍了lua语言中闭包的特性及其在模式匹配、日期处理、编译和模块化等方面的应用。lua中的闭包是严格遵循词法定界的第一类值,函数可以作为变量自由传递,也可以作为参数传递给其他函数。这些特性使得lua语言具有极大的灵活性,为程序开发带来了便利。 ... [详细]
  • Mac OS 升级到11.2.2 Eclipse打不开了,报错Failed to create the Java Virtual Machine
    本文介绍了在Mac OS升级到11.2.2版本后,使用Eclipse打开时出现报错Failed to create the Java Virtual Machine的问题,并提供了解决方法。 ... [详细]
  • 本文讲述了作者通过点火测试男友的性格和承受能力,以考验婚姻问题。作者故意不安慰男友并再次点火,观察他的反应。这个行为是善意的玩人,旨在了解男友的性格和避免婚姻问题。 ... [详细]
  • 本文详细介绍了Linux中进程控制块PCBtask_struct结构体的结构和作用,包括进程状态、进程号、待处理信号、进程地址空间、调度标志、锁深度、基本时间片、调度策略以及内存管理信息等方面的内容。阅读本文可以更加深入地了解Linux进程管理的原理和机制。 ... [详细]
  • 1,关于死锁的理解死锁,我们可以简单的理解为是两个线程同时使用同一资源,两个线程又得不到相应的资源而造成永无相互等待的情况。 2,模拟死锁背景介绍:我们创建一个朋友 ... [详细]
  • 后台获取视图对应的字符串
    1.帮助类后台获取视图对应的字符串publicclassViewHelper{将View输出为字符串(注:不会执行对应的ac ... [详细]
  • Java验证码——kaptcha的使用配置及样式
    本文介绍了如何使用kaptcha库来实现Java验证码的配置和样式设置,包括pom.xml的依赖配置和web.xml中servlet的配置。 ... [详细]
  • 在project.properties添加#Projecttarget.targetandroid-19android.library.reference.1..Sliding ... [详细]
  • CentOS 7部署KVM虚拟化环境之一架构介绍
    本文介绍了CentOS 7部署KVM虚拟化环境的架构,详细解释了虚拟化技术的概念和原理,包括全虚拟化和半虚拟化。同时介绍了虚拟机的概念和虚拟化软件的作用。 ... [详细]
  • 本文介绍了一种解析GRE报文长度的方法,通过分析GRE报文头中的标志位来计算报文长度。具体实现步骤包括获取GRE报文头指针、提取标志位、计算报文长度等。该方法可以帮助用户准确地获取GRE报文的长度信息。 ... [详细]
author-avatar
dashan
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有