随着移动互联网的普及,被越来越多的心怀不轨的人觊觎,也越来越多的安全问题暴露了出来。开发者开发出来的应用被安装在设备上之后,用户并不具有专业的安全知识。因此,开发者有义务为用户的安全保驾护航,能够为用户提供可信赖的服务才会被其青睐。
攻击者在暗,我们在明,我们不知道对方会使用怎样的方式威胁到应用的安全。因此我先就最坏的情况来考虑,即会有人恶意去逆向我们的应用,我们应该怎么样去应对这些可能出现的危险。
常用的逆向分析手段
要知道怎么防备,我们就需要知道一些常用的逆向分析方式,这样才能知己知彼。通常来说分析有三种手段:
-
静态分析
静态分析这一阶段主要会利用给各种工具,来帮助开发者分析目标软件,常用的工具有比如Hopper、IDA、Keychain-Dumper、Class-dump等。
其中IDA是效果最好也是最贵的,代码还原度很高,基本上可以照着理清楚代码的逻辑了。
-
动态分析
动态分析是指在软件运行的过程中进行调试分析。在iOS中runtime扮演了一个很重要的角色,我们在动态分析的过程中往往也是借助了runtime的强大能力来进行的,比如我们可以动态地更改代码的行为、可以获取到当前的视图层次等等。这一部分我们可以利用的工具有包括Cycript、Reveal、LLDB等。
-
网络分析
流量分析是指利用像Charles这样的抓包分析工具,分析应用的流量信息,安全意识比较差的公司做的一些产品我们往往能从中得到一些敏感信息。
如何防?
攻击者往往会从以上这几个点去查找你的应用中可能存在的漏洞,一旦找到了他们的切入点,下一步相对来说会简单一点。在接下来的内容中,针对以上几点围绕着二进制安全、数据安全以及网络安全来讲述。
二进制安全
攻击者会拿到我们的应用进行分析,然后可能会篡改我们的执行文件或者是资源文件,因此我们有必要采用一些手段来防止他们窥探以及对应用的行为进行修改:
-
防止调试器依附
通常黑客可能会通过gdb或者lldb来调试我们的应用以验证代码的行为,为后一步攻击做准备。而调试器之所以能够工作是因为Ptrace的存在,它为调试器提供了监控目标进程的机会。因此,通常情况下,我们在应用中禁用掉它,这可以参考我之前写的这篇文章以及github的demo。
-
越狱检测
当应用被安装在一台越狱后的设备之后,它所面临的安全风险就会相对来说大很多。而可能处于安全性的考虑,可能我们并不希望我们的应用运行在这样的环境下,因此我们可以通过一些检测来判断是否处在越狱的设备上。通常来说越狱设备上会安装Cydia、MobileSubstrate等。我们可以在代码中检测Applications下是否有相关应用存在,如果存在就可以给用户相应的提示并进行处理。
-
敏感字符串安全
编译之后的应用中对已经初始化的字符串依然是可见的,把应用丢到IDA或者Hopper中很容易就看到一些敏感字符串的值了。因此字符串的加密处理是很有必要的,比如我们可以用一些简单的加密算法加密特别敏感的字符串,这样初始化出来的字符串是一串不可读的问题,需要使用的时候再进行解密。
-
混淆
这一步主要是为了迷惑敌人的视线,提升分析难度。编译的时候可以通过脚本加入无意义的代码以及将正常的字符串替换为无意义的代码。但是这样的方式会给自己在维护的时候带来一定困难,比如你的代码通过混淆后发生了crash,通过dsym符号表解析出来的崩溃信息也变得不可读了,还得对照混淆时候的映射表来查看,所以需要三思这个到底值不值得做。
除此之外,我们还可以混淆文件名。前几天想逆向看看滴滴的模块化是如何做的,无意发现了一张很有意思的图片,后缀表示是一个图片,但是实际上是个存有字符串的文件。我们可以用类似的方式伪装一些相对重要的文件。
-
敏感业务用更安全的语言
OC是一门具有动态特性的语言,这给了攻击者很多机会去修改你原有代码的行为,甚至是加上新的代码。因此在核心部分可以使用更加安全的代码,比如我们可以使用C甚至汇编去写。往简单来说用Swift来写代码都比OC一定程度上来得安全。
-
自检
我们可以对二进制文件或者资源文件进行md5,然后交给我们的server去比对是否来自一个合法的应用,这一定程度上也能够提供一些防护性。
数据安全
我们的应用可能会在本地存储一系列的文件,包括用户数据,数据库文件,甚至在日益兴起的Hybrid开发或者是各种Patch方式中我们会下载的源码文件。我们应该尽可能地确保这些文件不会轻易被窃取到,即使窃取到了之后黑客也没办法使用。
-
数据保护
我们需要将类似用户密码这样的敏感数据存到keychain中。我们还会在本地存储多种类型的文件,其中可能会包含一些敏感信息。我们在使用的时候是可以设置其访问安全限制的。比如下面在使用FileManager的时候使用 FileProtectionType.complete 用以保证文件只有在设备未被锁定时才可访问。同样在使用Keychain的时候也有类似的做法。
try? FileManager.default.setAttributes([.protectionKey: FileProtectionType.complete], ofItemAtPath: "your path ")
-
数据擦除
有些敏感数据我们希望用完就把它给干掉,不留一点痕迹。比如用户在输入密码进行登录的时候,我们的viewModel上有一个叫做password的property。登录完成之后,我们即使把这个属性置为空之后值都依然在内存当中,这个时候我们可能需要手动地把这些敏感内容给擦掉。
-
防止键盘缓存
键盘的自动更正机制会缓存用户的输入,如果在一台越狱设备上的话很可能被第三方应用轻易地读取到缓存中的数据。
简单来说我们可以把UITextfield的autocorrectionType属性设置为No来关掉这个功能。在一些安全性要求较高的应用当中通常会自定义键盘,这样可以防止缓存被第三方应用读取到也能够防止被录屏(系统键盘按下有效果)。
网络安全
-
不传输明文
我们不应该在网络中明文传输敏感数据。否则即使在没越狱的手机上,很容易遭到中间人攻击,黑客可以轻而易举地获取到用户的敏感数据。
-
使用https
苹果本来准备强制要求的,不知道为何搁浅了,重要性不言而喻。
-
使用更安全的协议
比如我们可以使用二进制协议或者是自定义协议来提高安全性。
-
Hybrid应用安全
如今React Native、Cordova等应用得越来越广,安全性也变得越来越重要。
在这样的开发中,Mobile扮演的角色就是一个浏览器,因此在前端开发中常用的防护手段也在此使用,比如JS代码混淆、XSS防护、加密传输等。
非恶意攻击造成的安全问题
以上大部分都是一些比较恶意的针对终端用户的攻击防护,所谓防君子不防小人,想要搞破坏的人总是会找到办法的。我们也还应该注意一些无意之间容易造成的安全问题。
- 应用退到后台
苹果会在应用退到后台的时候进行截屏,会将当户当前的状态截图保存下来,这可能会在无意之中造成用户数据的泄漏,因此我们可能需要主动地替换掉这张截图。
-
警惕iCloud备份
用户在开启iCloud的情况下,可能会自动对文件目录进行自动备份,我们需要指定包含敏感信息的文件不能进行备份。
-
注意Touch ID的变化
自从iPhone有Touch ID之后大大的方便了用户的使用,比如我们可以按一个手指就进行支付、登录等操作。我们在开发这样的业务逻辑的时候,应该考虑到这样的场景,会不会因为一些正常情况下手机借给朋友造成了信息或者财产的流逝。
-
防止类似XcodeGhost事件再次发生
早前发生的XcodeGhost事件掀起了一阵波澜,让我们意识到,即使是非越狱设备上也可能由于疏忽造成一些安全问题,因此我们需要警惕类似的事件再次发生。
总结:
道高一尺魔高一丈,如果终端不在用户手中,总是能够见招拆招的。作为开发工程师的我们虽然不需要具备很强的安全能力,但是我们需要了解一些基础的知识并具有一定的安全意识,尽可能地为我们的产品和用户负责。