JSPatch 部署安全策略

2015-8-31

使用 JSPatch 有两个安全问题:

  1. 传输安全:JS 脚本可以调用任意 OC 方法,权限非常大,若被中间人攻击替换代码,会造成较大的危害。
  2. 执行安全:下发的 JS 脚本灵活度大,相当于一次小型更新,若未进行充分测试,可能会出现 crash 等情况对 APP 稳定性造成影响。

接下来说下这两个问题的解决方案。

传输安全

方案一:对称加密

若要让 JS 代码传输过程中不轻易被中间人截获替换,很容易想到的方式就是对代码进行加密,可以用 zip 的加密压缩,也可以用 AES 等加密算法。这个方案的优点是非常简单,缺点是安全性低,容易被破解。因为密钥是要保存在客户端的,只要客户端被人拿去反编译,把密码字段找出来,就完成破解了。

对此也有一些改进方案,例如:

1.可以把密码保存到 keychain 上,但这种方式也是不可靠的,只要随便找一台机器越狱装了这个 APP,用 hook 的方式在 APP 上添加一些代码,获得 keychain 里的密钥值,就可以用于其他所有机器的传输解密了。

2.给每个用户下发不同的密钥。但这样就非常繁琐,需要对下发密钥的请求做好保护,后台需要每次都对脚本进行不同密钥的加密操作,复杂性高了。

综上,对称加密安全性低,若要稍微提高点安全性,就会提升程序复杂度。

方案二:HTTPS

第二个方案是直接使用 HTTPS 传输,优点是安全性高,只要使用正确,证书在服务端未泄露,就不会被破解。缺点是部署麻烦,需要使用者服务器支持 HTTPS,门槛较高。另外客户端需要做好 HTTPS 的证书验证(有些使用者可能会漏掉这个验证,导致安全性大降),具体的认证方式可见网上一些文章,例如这篇。如果服务器本来就支持 HTTPS,使用这种方案也是一种不错的选择。

方案三:RSA 校验

有没有安全性高,部署简单,门槛低的方案?RSA 校验就是。

这种方式属于数字签名,用了跟 HTTPS 一样的非对称加密,只是简化了,把非对称加密只用于校验文件,而不解决传输过程中数据内容泄露的问题,而我们的目的只是防止传输过程中数据被篡改,对于数据内容泄露并不是太在意。整个校验过程如下:

JSPatchSecurity

  1. 服务端计算出脚本文件的 MD5 值,作为这个文件的数字签名。
  2. 服务端通过私钥加密第 1 步算出的 MD5 值,得到一个加密后的 MD5 值。
  3. 把脚本文件和加密后的 MD5 值一起下发给客户端。
  4. 客户端拿到加密后的 MD5 值,通过保存在客户端的公钥解密。
  5. 客户端计算脚本文件的 MD5 值。
  6. 对比第 4/5 步的两个 MD5 值(分别是客户端和服务端计算出来的 MD5 值),若相等则通过校验。

只要通过校验,就能确保脚本在传输的过程中没有被篡改,因为第三方若要篡改脚本文件,必须计算出新的脚本文件 MD5 并用私钥加密,客户端公钥才能解密出这个 MD5 值,而在服务端未泄露的情况下第三方是拿不到私钥的。

这种方案安全性跟 HTTPS 一致,但不像 HTTPS 一样部署麻烦,一套代码即可通用。对于它的缺点:数据内容泄露,其实在传输过程中不泄露,保存在本地同样会泄露,若对此在意,可以对脚本文件再加一层简单的对称加密。这个方案优点多缺点少,推荐使用,目前 JSPatch 平台就是使用这个方案。

最后有个小问题,保存在客户端的代码也可能被人篡改,需不需要采取措施?这个要看各人需求了,因为这个安全问题不大,能篡改本地文件,差不多已经有手机所有权限了,这时也无所谓脚本会不会被篡改了。若有需要,可以加个简单的对称加密,或者按上述流程每次都验证一遍MD5值。

执行安全

对于中大型 APP,下发 JS 脚本需要谨慎,有可能因为疏忽下发了有问题的代码,导致大量 APP crash,或一些其他异常情况,需要有一些机制避免这种情况。若要做得完整,可以分为:事发前(灰度),事发中(监控),事发后(回退)。

灰度

首先需要在事发前把出现问题的影响面降到最低,对于中大型 APP,不能一次把脚本下发给所有用户,需要有灰度机制,也就是一开始只下发给其中一部分用户,看看会不会出现异常情况,再逐步覆盖到所有用户。有条件的话灰度的用户最好按机型/系统/地域等属性随机分配,尽量让最少的人覆盖到大部分情况。

监控

接着是事发了我们需要知道脚本有问题,需要对 APP 有一些监控机制,像 crash 监控,这个一般所有 APP 都有接入,再按需求自行加入其他监控指标。

回退

最后是事发后回退代码。一般为了避免不可预料的情况出现,JSPatch 脚本建议在启动时执行,APP 运行过程中不去除,所以这个回退建议的实现方式是后台下发命令,让 APP 在下次启动时不执行 JSPatch 脚本即可。

但这里能回退的前提是 APP 可以接收到后台下发的回退命令,若因为下发的脚本导致 APP 启动即时 crash,这个回退命令也会接收不到。所以建议再加一层防启动 crash 的机制,APP 在连续启动即 crash 后,下次启动不再执行脚本文件。

灰度和监控中小型 APP 可以考虑不用,回退机制是每个使用 JSPatch 都建议加上的。目前 JSPatch 平台实现了上述回退方案。

分类:技术文章
评论

*

*

2015年8月31日 14:04

本质上来说,方案三相当于对脚本进行签名,建议使用成熟的消息签名算法,而不是重新发明一种自制的算法。另外 MD5 算法很容易找到碰撞,应当在任何应用中禁止使用

2015年8月31日 17:47

这里用的就是RSA算法,没发明自制算法。就MD5的碰撞概率,在此例子中用于校验文件是足够可靠的。

2015年9月6日 11:00

1、灰度
我觉得可以采用添加测试设备方式,现下发给测试设备,通过之后再发给所有用户
2、回退
服务端提供接口,需要本地执行脚本就返回脚本信息,不需要本地执行就返回空

2015年9月16日 10:21

JSPatch 能通过 appstore 审核么?

2015年9月16日 10:23

多个APP已接入JSPatch通过审核,有一例被拒,不过被拒的主要原因应该不是JSPatch

2015年9月16日 10:50

谢谢

2015年10月8日 18:16

测试发现 JSPatch 平台提供的 SDK,是优先加载缓存的 Patch ,然后去更新服务器的 Patch 到缓存, 出现两个问题。
1、更新 Patch 文件后,需要 APP 重新启动两次才能加载到新的 Patch 。
过程:第一次重新启动加载缓存 Patch ,并更新更新服务器的 Patch 到缓存;第二次重新启动加载缓存的 Patch (也就是更新后的 Patch )。
2、出现 Patch 文件在 APP 启动时加载出现 crash ,就没有机会更新并修证缓存中的 Patch 文件了。
不修改 SDK 是否有解决办法?还是只能修改 SDK ?

2015年10月17日 17:32

您好,RSA加密应该是用公钥加密,用私钥解密吧,因为公钥是公开的,倘若用公钥解密,岂不是相当于没有加密,见http://www.ruanyifeng.com/blog/2013/06/rsa_algorithm_part_one.html

2015年10月17日 18:32

这里加解密是为了防篡改,而不是防内容被看到。

2015年10月18日 12:49

明白了,多谢指教

2016年1月28日 16:35

你好,“防启动 crash 的机制” 这个怎么实现啊。是不是可以用后台线程纪录崩溃次数?

[…] RSA 非对称加密传输就不会有问题。加密方式可以参考之前的文章《JSPatch 部署安全策略》,以及项目自带的 JPLoader […]

2016年2月16日 16:00

你好,也想问问“防启动 crash 的机制” 这个怎么实现

2016年2月16日 16:01

你好,也想问问 JSPatch 平台是怎么实现“防启动 crash 的机制”

2016年2月17日 16:33

请教一下;
貌似 openssl 只提供了用公钥加密的工具。
博主用什么工具做的私钥加密?

2016年2月25日 20:14

有了https。就不用其他的加密方式了吧。比如aes,des,rsa

[…] The author of JSPatch has discuss about the security issue in this article JSPatch 部署安全策略 […]

[…] JSPatch部署安全策略。对 JPLoader 的使用方式可以参照 wiki […]

2016年3月22日 15:05

搞明白了,openssl 中
公钥加密 = 加密
私钥解密 = 解密
私钥加密 = 签名
公钥解密 = 验证

2016年3月24日 11:46

[…] 小版本升级jspatch技术,安全性,需要自行使用签名校验 […]

2016年4月6日 16:40

对加密这种东西不太懂。想问您一下,明文传输会暴露接口嘛? 先对js内容进行SHA得到A,再对js内容用私钥加密得到B, 将A、B传给客户端,客户端用公钥对B解密,之后对结果进行SHA,判断和A是否相等。每次使用j s的时候,先用公钥解密再使用。这样可以吗?

2016年4月12日 0:30

https://github.com/SwiftLOL/ExceptionCatcher 看看我这个想法怎么样,可行吗

2016年7月7日 14:20

https一样可以通过抓借口获取并串改你的数据

2017年4月19日 11:11

上面的名为”abenr”读者说『https一样可以通过抓借口获取并串改你的数据』。
是的,是可以,作为手机的主人,你都有超级权限了,什么数据你改不了。
但是,作为另一个角色:中间者,他目前是无能为力的。可能你做过逆向,但你对信息安全的理解还欠深度。