iOS App 签名的原理

2017-3-13 评论(26) 分类:技术文章

iOS 签名机制挺复杂,各种证书,Provisioning Profile,entitlements,CertificateSigningRequest,p12,AppID,概念一堆,也很容易出错,本文尝试从原理出发,一步步推出为什么会有这么多概念,希望能有助于理解 iOS App 签名的原理和流程。

目的

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

非对称加密

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

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

  1. 选两个质数 p 和 q,相乘得出一个大整数n,例如 p = 61,q = 53,n = pq = 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) 这两个数据就是私钥,满足用私钥加密,公钥解密,或反过来公钥加密,私钥解密,也满足在只暴露公钥 (只知道 n 和 e)的情况下,要推导出私钥 (n,d),需要把大整数 n 因数分解。目前因数分解只能靠暴力穷举,而 n 数字越大,越难以用穷举计算出因数 p 和 q,也就越安全,当 n 大到二进制 1024 位或 2048 位时,以目前技术要破解几乎不可能,所以非常安全。

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

数字签名

现在知道了有非对称加密这东西,那数字签名是怎么回事呢?

数字签名的作用是我对某一份数据打个标记,表示我认可了这份数据(签了个名),然后我发送给其他人,其他人可以知道这份数据是经过我认证的,数据没有被篡改过。

有了上述非对称加密算法,就可以实现这个需求:

(更多…)

关于苹果警告

2017-3-9 评论(33) 分类:互联网

昨天早上 iOS 开发者们陆续收到苹果邮件,警告去掉动态下发功能,覆盖面很广,内容没有明确指示是什么库,导致大家各种猜测。

其实上周已经有少量用户收到苹果这份警告邮件,当时还以为是特例,现在看来是在灰度测试扫描代码,可见这事苹果应该讨论已久,并专门排期开发测试了扫描程序,直到昨天才正式上线。

从各方信息看起来,很不幸主要禁的还是 JSPatch / wax/ rollout 这样的热修复框架,特点是可以通过 JS 脚本调用和替换任意 OC 方法,而像 React Native/ 小程序这样用 JS 做功能的暂时不受影响,Weex 不确定,至于其他库像 AFNetworking / SDWebimage 用到那几个接口的,应该只是误伤。

根据苹果要求,收到警告的同学只需要在下次提交版本时去掉相关框架就可以,没有时间期限,目前也不会强制下架。

为什么

苹果为什么这么做呢?苹果对热修复一直以来的态度都是不赞同也不拒绝,JSPatch 本身也并没有违反开发者条例,而且 JSPatch 大多数都用于修复 bug,提升 iOS 平台 App 的质量,对苹果也是件好事,为什么要禁?猜测原因有两点:可控和安全。

可控

苹果一贯作风是让所有事情可控,开发者能用什么不能用什么都尽量在自己的控制范围内。大多数人使用 JSPatch 修复 bug,或者弄一些临时运营的小功能配置,这些没有问题,但总会有少数用户使用 JSPatch 去调用私有API做些事,这是苹果不可控的,也无法知道有多少人这样做了。

不过其实在代码这块苹果其实一直可控程度有限,他会在提交时扫描你有没有用某些私有方法,但只要你对这些私有方法调用做一些变化,加解密字符串拼接什么的,就能绕过扫描,再通过后台配置调用,是一样的。JSPatch 只是让调用私有 API 变得成本更低更方便点而已,可控这里只是个小理由。

安全

去年 FireEye 分析了使用 JSPatch 的安全问题,当时我也写文章回应了,再复述一下,主要安全风险有三点:

  1. 开发者自己本身对 APP 下发恶意代码。
  2. 开发者没有做好加密传输和校验。
  3. 开发者接入的SDK里接入了JSPatch,SDK 作者可以对这些 APP 下发恶意脚本。

第一点其实不算安全风险,因为开发者自己有恶意的话完全不需要借助 JSPatch。

第二点大多数用户使用 JSPatch 时都做好了非对称加密,保证不会在传输过程被第三方篡改。但这里技术上没法保证用户一定使用正确的加密方式,苹果无法知道有多少接入 JSPatch 的用户没有正确加密和校验,这是未知的安全隐患。

第三点在当时并没有什么第三方 SDK 接入 JSPatch,但现在像高德地图/个推等都接入了,如果他们要作恶,或者他们本身服务端被入侵,确实是个安全隐患。

iOS 平台是最安全的,也是最注重安全的,即使热修复带来了 App 质量更高的好处,也无法无视这里的安全隐患,现在 JSPatch 国内覆盖面很大,若出一个安全问题,会影响 iPhone 的声誉,因为这个风险,所以考虑禁掉。

反应

这个警告出来后,国内开发者有各种反应,各种表情贴图还挺搞笑的,不过大家放心,JS没事,iOS 开发该失业的还是失业:)

看到有一些人拍手称赞,赞的理由不是说苹果维护了平台安全,而是:1.国内开发方式low,2.产品经理滥用。这里我有一些想法说一下。

开发方式

他们说国外开发不理解国内为什么要用热修复,国外很少使用,国外开发流程很好很规范,会做好充分的 codereview 和测试,上线后没什么 bug,不需要热修复,也不会有产品经理乱提需求,迭代没像国内这么快,使用热修复是本末倒置,不去考虑提高 APP 质量,国内开发方式太 low,国外的才是正道。

这里有个问题,就是什么是好的开发方式?以什么标准界定?上面的说法可以看出他们是把工程的严谨性,流程的规范性作为好坏的依据。虽然我是个程序员,觉得工程严谨和流程规范确实是好东西,但我比较实用主义,更倾向于以结果作为标准,也就是能不能更低成本更高效地开发出质量更好的产品作为标准。

如果我使用热修复能以更低的人力成本(工程师能力和薪水不如国外,人数少),更高效(测试时间缩短,不需要覆盖到0.01%几率出现的 bug / crash ),做出质量更高的产品( bug / 特殊情况和需求反应速度快),为什么不是一个更好的开发方式呢?

另外客户端的开发方式本身就是落后的,不利于快速迭代,无法对线上产品有控制权,参考另一篇文章。这也就是为什么 Facebook 一开始要用 web hybird 的方式开发,现在又要做 React Native。热修复是这种落后开发方式的弥补。另外我没在国外公司工作过,但感觉他们对bug的容忍程度还是比国内高的,对比一下 IAP 和微信支付的失败率,做过的人都知道。

还有一个声音说国内的人喜欢违反规则,钻空子太不老实。首先前面也说了热修复的方式并没有违反规则,完全符合开发者条例,其次国外也有热修复 rollout,最后如果从开发者条例来说,React Native 反而是违反规则的,因为主要用途动态添加和修改 APP 的功能。

滥用

另一个说法是上了热修复后产品经理来劲了,产品时不时想到一个功能配置说上就上,开发者弱势只能跟着上。

这种情况在我这边团队还没遇到过,我的想法是:如果要上的功能配置对产品是有好处有必要的,开发维护成本又低,为什么不上?如果要上的功能配置是无关紧要的,或者开发维护成本太高,为什么不能讲理拒绝?

开发者把原因定位为自己“弱势”,就把自己从团队剥离开了,变成对人不对事,这种团队氛围是挺糟糕的,而这个锅也不是产品经理的。大家做的事都是为了产品更好,应该不会有那么多故意刁难不讲理的产品经理和老板。至于怎样界定对产品有没有好处和有没有必要,以及开发成本高低,这得自己协商了,以我们团队的做法是以做这个事的性价比计算。

怎么办

接下来如果还想用 JSPatch 怎么办?我没有跟苹果审核团队交流过,不知道他们的想法,短时间内是先不要用,后续再看情况。

热修复的需求很大,很希望苹果可以推出自己的方案,由系统做这个事是可以保证安全的,但现在看起来可能性较低,国外需求量不大,苹果也就不会重视这个需求,何况目前在大力推 Swift。

对于 JSPatch,苹果应该是扫描可执行文件里的关键字,从技术上说是很难禁掉的,可以做各种混淆去绕过检查,但若下发时被查到,会有政策风险,政策有待观察。

实际上动态化还是处于灰色地带,严格来说 RN 是不符合规则的,但还是被允许,只要不给苹果添麻烦,苹果就不会管,JSPatch 因为上面提到的两点风险被管了,怎样做到使用并不给苹果添麻烦呢?

  1. 减少自行接入的使用人数。
  2. 禁止 SDK 接入。
  3. 接入保证传输安全和只用于修复 bug。

第一点警告邮件和代码检查使得自行接入 JSPatch 门槛变高了,显然会减少使用人数。第二点第三点只要有一个平台来管控,由平台保证安全性以及扫描下发的脚本,禁止私有API调用,禁止大量脚本下发,是可以做到的,可能的话希望能跟苹果审核团队协商。

附上 JSPatch 平台初定的解决方案

iOS 开发技术栈与进阶

2017-2-28 评论(17) 分类:技术文章

最近有一些开发朋友问我应该怎样提升自己的能力,回想起来做了这么久 iOS 开发,我也有过那种“让我做一个功能实现个需求我会做,但接下来怎样提高我不知道。”的时期,这里尝试列一下 iOS 开发的相关技术,再说说在学习进阶上我的一些想法。

iOS 技术栈

这里按我的理解给 iOS 相关技术分个类,以工程实现的角度,分成了基础、需求、效率、质量四个类别。基础指程序开发和 iOS 开发的基础知识和技能,需求就是产品的需求,有了基础技能,实现了产品需求后,剩下的事情就都是为了提高项目质量和提升开发效率。

大致的思维导图

iOS技术栈 (更多…)

如何动态创建 block – JPBlock 扩展原理详解

2017-1-23 评论(12) 分类:技术文章

简介

JSPatch 最近新增了扩展 JPBlock,解决之前 block 使用上的一些限制:

  1. block 参数个数最多支持6个。
  2. block 参数类型不能是 double / struct / union 类型。
  3. 不支持 JS 封装的 block 传到 OC 再传回 JS 去调用。

接入 JPBlock 后,就可以:

  1. block 参数支持任意多个。
  2. block 参数类型可以是除 struct / union 以外的任意类型,包括 double。
  3. 支持 JS 封装的 block 传到 OC 再传回 JS 去调用。

这篇文章说说这里的实现原理。

(更多…)