
现在很多 iOS 的 app 没有做任何的安全防范措施。今天我们就聊聊 iOS 开发人员平时怎么做才更安全。
一、网络方面
用抓包工具可以抓取手机通信接口的数据。以 Charles 为例,用 Charles 可以获取 http 的所有明文数据,配置好它的证书后就可以模拟中间人攻击,获取 https 加密前的明文数据。
先简要的说下什么是中间人攻击:
①客户端:“我是客户端,给我你的公钥” -> 服务端(被中间人截获)。
所以现在是:
客户端->中间人,
②然后中间人把消息转给服务端,也就是:
中间人->服务端。
③服务端把带有公钥的信息发送给客户端,但是被中间截获。所以是:
服务端-[服务端的公钥] ->中间人。
④中间人把服务端的公钥替换成自己的公钥,发送给客户端,声称是服务端的公钥:
中间人-[中间人的公钥] ->客户端
⑤客户端用得到的公钥加密,实际是用的中间人的公钥进行的加密,所以中间人可以用自己的私钥解密,获取原始数据,然后再用服务端的公钥对原始数据(或者修改原始数据内容)加密后发送给服务端。
这样中间人就可以获取到双方的通信数据,并可以制造虚假数据。
下面开始说如何防范:
1、SSL Pinning
SSL Pinning 的原理就是把服务端的公钥存到客户端中,客户端会校验服务端返回的证书是否和客户端保存的一致,这样就避免了中间人替换证书进行的攻击。
SSL Pinning 的实现比较简单,只需要把 CA 证书放入项目中,通过 Security framework 实现 NSURLSession 上的 SSL Pinning。如果用的是 AFNetworking,代码更简单一点:

这样通过 Charles 抓包就会报错。

证书验证有可以只验证公钥(AFSSLPinningModePublicKey),也可以完全验证证书(AFSSLPinningModeCertificate)。
但是用 SSL Pinning 有个很严重的问题,就是如果证书有问题,只有发布新版本才能解决。如果新版本一直审核不通过,app 的网络通信就全部挂掉了。
比如赛门铁克(Symantec)证书被 google 和 iOS12 不信任的问题。如果 app 内置了证书,就必须要重新发版。
2、接口内容进行加密
很多的 app 接口只对请求的参数进行加密和各种验证,而接口返回过来的数据就是明文。如果不用 SSL Pinning 来防止中间人攻击,也可以把接口返回的数据也进行加密,这样抓包工具抓到包后也依然不能破解。
比如微信,微信中的接口用的是 http 协议,但是内容全部进行了加密。

现在常用的是对称加密,加密效率比较快。如果 app 里有的数据特别重要,还是要用非对称加密,非对称加密更安全,但是效率会比较慢。
二、日志
1、Swift 日志
Swift 中打印日志的语法可以用 print,也可以用 NSLog。但是尽量别用 NSLog,因为 Swift 中用 NSLog,系统日志中是能查到的。可以通过 pp 助手、iTools 或者 Xcode 的 Devices and Simulators 来查看系统日志。
用 print 打印日志就不会出现在系统日志中。
2、OC 日志
在 release 环境下不要输出 NSLog 日志。一般大家都会用宏定义解决,如下:

三、信息的存储
1、密钥
大部分的程序员喜欢直接把密钥放到宏或者常量里。
如:#define AES_KEY @“aaa123"
这样做很容易就可以被反编译出来。安全性比较差。可以用以下方法加强安全,增加破解的难度。
1.1、对密钥(A)进行加密后定义为宏(B),使用的时候进行解密得到密钥(A)。其中对密钥 A 加密的密钥为 C。
因为在宏定义的时候我们如果定义成字符串,会直接存在 data 段,这样破解者很容易获取到。比较安全的做法是把 C 和 B 定义成 uint8_t[]数组,这样每个字符就会放到 text 段的每个单独指令中。指令执行后生成字符串。这样就会很安全。
1.2、用一段长文本,按规则提取出里面的密钥,密钥是随机的。
在服务端和客户端定义一段长文本,app 端随机生成起始位置和长度,把起始位置和长度进行移位等操作,生成相应的数字,对数字进行 Base64 编码,生成的字符串 传给服务端,服务端根据这个字符串 就能 解析出相关的密钥。
代码如下:

这样只是增加了破解者获取密钥的难度,其实并不能完全阻止破解者获取。
2、Keychain
越狱的 iPhone 可以查看导出 Keychain 保存的信息。Keychains 的内容存放在 sqlite 中,目录为:/private/var/Keychains。可以通过 keychain-dump 可以查看钥匙串里存放的的内容。
所以保存到 Keychain 的数据一定要是加密之后的数据。
3、plist、sqlite
plist、sqlite 可以直接在 ipa 安装文件中获取到,所以不要在这些文件中存放重要信息,如果要保存,就进行加密后再存放。
四、app 加固
1、代码混淆
代码混淆就是把易读的类名、方法名替换成不易读的名字。常用的方法有宏替换和脚本替换。
比如本来方法名为:- (void)loadNetData; 进行代码混淆后,用 class-dump 导出头文件后会显示成修改后的方法名:- (void)showxhevaluatess;
2、用 C 语言
核心代码用 C 语言写,但是 C 语言的函数也可以被 hook,比如用 fishhook。开发人员可以用静态内联函数来防止 hock,破解者就只能去理解代码的逻辑。
3、检测 tweak
可以检测 /Library/MobileSubstrate/DynamicLibraries 下的 plist 文件里是否包含自己 app 的 bundle id。如果包含,可以进行限制 app 的功能、提示该手机不安全 等。
本文转载自宜信技术学院网站。
原文链接:http://college.creditease.cn/detail/161
评论