iOS应用安全开发概述

【摘要】:iOS应用由于其直接运行在手机上,相比运行在服务器的后台服务,更有可能被黑客攻击。本文将从网络安全、本地文件和数据安全、源代码安全三个方面,阐述iOS应用在安全性上遇到的挑战。

前言

在传统互联网领域,安全已经是一个老生常谈的话题。在许多大公司里面,都设置有专门的安全部门,用于检测自己产品的安全性。但即便是这样,业界仍然时常暴出许多安全问题的新闻。就在不久前,乌云曝光了携程网在支付过程中,为了调试方便,记录了用户的信用卡卡号和CVV码等信息,而调试接口可以被外网访问,这样造成黑客可能通过调试接口读取用户的信用卡信息。虽然最终没有造成实际上的用户损失,但是此次事件再一次给互联网公司敲响了安全的警钟。

除了国内,国外的互联网安全问题同样让人担忧。去年由于曝出Apache Struts2的漏洞,苹果公司多次重置开发者的密码,并且最终为了用户数据的安全,将整个开发者后台全部停止服务,花了2周多时间将后台有潜在问题的功能重写后,才重新开放服务。而4月份刚刚曝光的OpenSSL的heart bleeding漏洞,则让全球的三分之二的网站受到影响。

在移动互联网快速发展的今天,iOS应用由于直接运行在用户的手机上,相比运行在服务器的后台服务,更有可能被黑客攻击。本文接下来将从三个方面概述iOS移动应用在安全方面所面临的挑战以及应对措施。

一、网络安全

安全地传输用户密码

大部分的iOS应用都需要联网,通过和服务器端进行通讯,获得最新的信息并且将内容展现给用户。由于网络传输过程中有可能经过不安全的中间节点,所以我们应该对敏感数据加密,用于保证用户信息的安全。黑客可以在受害者的手机上设置网络通讯的代理服务器,从而截获所有的网络请求。即使是Https的加密通讯,黑客也可以通过中间人攻击(Man-in-the-middle attack,一种是指攻击者与通讯的两端分别创建独立的联系,并交换其所收到的数据,使通讯的两端认为他们正在通过一个私密的连接与对方直接对话,但事实上整个会话都被攻击者完全控制)来截取通讯内容。

黑客可以在Mac下使用Charles软件(如果在Windows下,可以使用fiddler软件)来将自己的电脑设置成代理服务器,从而截取应用的网络请求,分析目标应用在通讯协议上是否有安全问题。为了测试,我选取了在国内最大的两家租车公司(神州租车一嗨租车)的iOS应用。

从下图可以看到,神州租车和一嗨租车在用户登录时,均采用明文的方式,将密码直接发送给服务器。其中一嗨租车不但采用明文方式发送密码,而且在发送时使用了Http Get的方式,而GET的URL数据一般都会保存在服务器的access log中,所以黑客一旦攻破服务器,只需要扫描acesss log,则可以轻易获得所有用户的明文密码。(注:在本文发表前,一嗨租车已经修改了登录协议,采用了POST的方式来登录,但仍然传递的是明文密码)

神州租车登录协议:

一嗨租车登录协议:

如果每一个移动移动都像以上两种应用那样,明文传输用户密码,那么我们可以想象这样一个场景,黑客在咖啡馆或机场等一些公共场所,将自己的电脑设置成该场所一样名字的免费Wifi,那么受害者只要不小心使用了该Wifi,则可能泄漏自己的明文密码。对于大多数普通人,都会使用一样的密码登录他的所有的帐号,这就意味着他的其他帐号:例如淘宝或网上银行帐号也有被盗的风险。

正确的做法应该是这样:事先生成一对用于加密的公私钥,客户端在登录时,使用公钥将用户的密码加密后,将密文传输到服务器。服务器使用私钥将密码解密,然后加盐(Salt:在密码学中,是指通过在密码任意固定位置插入特定的字符串,让散列后的结果和使用原始密码的散列结果不相符)之后再多次求MD5,之后再和服务器原来存储的用同样方法处理过的密码匹配,如果一致,则登录成功。这样的做法,保证黑客即使截获了加密后的密文,由于没有私钥,也无法还原出原始的密码。而服务器即使被黑客攻陷,黑客除了暴力尝试,也无法从加盐和多次MD5后的密码中还原出原始的密码。这样就保证了用户密码的安全。

防止通讯协议被轻易破解

除了上面提到的明文传输密码的问题外,移动端应用还要面对黑客对于通讯协议的破解的威胁。在成功破解了通讯协议后,黑客可以模拟客户端登录,进而伪造一些用户行为,可能对用户数据造成危害。例如腾讯出品的消除游戏“天天爱消除”,在淘宝上就有很多售价仅为1元的代练服务,如果真正是人工代练,是不可能卖这么便宜的,只有可能是该游戏的通讯协议被破解,黑客制作出了代练的机器人程序。

通讯协议被破解除了对于移动端游戏有严重危害外,对于应用也有很大的危害。例如针对微信,黑客可以制作一些僵尸帐号,通过向微信公共帐号后台发送垃圾广告,达到赢利目的。而iPhone设备上的iMessage通讯协议据也被破解了,所以很多iPhone用户会收到来自iMessage的垃圾广告。

对于以上提到的问题,开发者可以选择类似protobuf(google提供的一个开源数据交换格式,其最大的特点是基于二进制,因此比传统的JSON格式要短小得多)之类的二进制通讯协议或者自己实现通讯协议,对于传输的内容进行一定程度的加密,以增加黑客破解协议的难度。下图是我截取的淘宝客户端的通讯数据,可以看到其中的值都不能直观地猜出内容,所以这对于通讯协议是有一定的保护作用。

验证应用内支付的凭证

iOS应用内支付(IAP)是众多应用赢利的方式,通过先让用户免费试用或试完,然后提供应用内支付来为愿意付费的用户提供更强大的功能,这种模式特别适合不习惯一开始就掏钱的中国用户。但是,由于国内越狱用户的比例比较大,所以我们也需要注意应用内支付环节中的安全问题。

简单来说,越狱后的手机由于没有沙盒作为保护,黑客可以对系统进行任意地修改,所以在支付过程中,苹果返回的已付款成功的凭证可能是伪造的。客户端拿到付款凭证之后,还需要将凭证上传到自己的服务器上,进行二次验证,以保证凭证的真实性。

另外,我们发现越狱用户的手机上,很可能被黑客用中间人攻击技术来劫持支付凭证。这对于黑客有什么好处呢?因为苹果为了保护用户的隐私,支付凭证中并不包含任何用户的帐号信息,所以我们的应用和服务器无法知道这个凭证是谁买的,而只能知道这个凭证是真的还是假的。所以在验证凭证时,哪个帐号发起了验证请求,我们就默认这个凭证是该帐号拥有的。如果黑客将凭证截获,就可以伪装成真实用户来验证凭证或者转手出售获利。

打个比方,这就类似于很多商场的购物卡一样,由于是不记名的,黑客如果将你买的购物卡偷窃然后去刷卡购物,商场是无法简单地区分出来的。

所以,对于应用内支付,开发者除了需要仔细地验证购买凭证外,也需要告知用户在越狱手机上进行支付的风险。

二、本地文件和数据安全

程序文件的安全

iOS应用大部分的逻辑都是在编译后的二进制文件中,但是由于今年来混合式(Hybrid)编程方式的兴起,很多应用的部分功能也采用内嵌Web浏览器的方式来实现。例如腾讯QQ iOS客户端的内部,就有部分逻辑是用Web方式实现的。由于iOS安装文件其实就是一个zip包,所以我们可以通过解压,看到包内的内容。以下是我解开腾讯QQ客户端,看到的其qqapi.js文件的内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
iOSQQApi = {
    // ...
    app: {
        /**
         查询单个应用是否已安装
         @param {String} scheme 比如'mqq'
         @return {Boolean}
         */
        isAppInstalled: function(scheme) {
            return iOSQQApi._invokeClientMethod(
                'app', 'isInstalled',
                {'scheme':scheme});
        },

        /**
         批量查询指定应用是否已安装
         @param {Array<String>} schemes 
                比如['mqq', 'mqqapi']
         @return {Array<Boolean>}
         */
        isAppInstalledBatch: function(schemes) {
            return iOSQQApi._invokeClientMethod(
                'app','batchIsInstalled',
                {'schemes':schemes});
        }
    },
    // ...
}

可以看到,这些文件都有着完整清晰的注释。通过分析这些javascript文件,黑客可以比较轻松地知道其调用逻辑。在越狱手机上,还可以修改这些javascript代码,达到攻击的目的。

笔者也曾经尝试查看支付宝客户端中的彩票功能,通过分析,也可以找到其完整的、带着清晰注释的javascript代码。如下图所示:(注:支付宝现在已经对相应代码进行了加密)

通过将javascript源码进行混淆和加密,可以防止黑客轻易地阅读和篡改相关的逻辑,也可以防止自己的Web端与Native端的通讯协议泄漏。

本地数据安全

iOS应用的数据在本地通常保存在本地文件或本地数据库中。如果对本地的数据不进行加密处理,很可能被黑客篡改。以下是一个名为 LepsWorld3 的游戏,打开它的本地文件,可以很容易地找到,它使用了一个名为 ItempLifes的变量保存生命数。如下图所示:

于是我们就可以简单修改该值,达到修改游戏参数的目的。而在淘宝上,也可以找到许多以此挣钱的商家,如下图所示:

对于本地的重要数据,我们应该加密存储或者将其保存到 keychain 中,以保证其不被篡改。

三、源代码安全

通过file, class-dump, theos, otool等工具,黑客可以分析已经编译之后的二进制程序文件,不过相对于这些工具来说,IDA的威胁最大。

IDA是一个收费的反汇编工具,对于Objective-C代码,它可以常常可以反汇编到可以方便阅读的程度,这对于程序的安全性,也是一个很大的危害。因为通过阅读源码,黑客可以更加方便地分析出应用的通讯协议和数据加密方式。

下图分别示例了一段代码的原始内容,以及通过IDA反汇编之后的结果。可以看到,IDA几乎还原了原本的逻辑,而且可读性也非常高。

原始代码:

1
2
3
4
5
6
if ([[VersionAgent sharedInstance] isUpgraded]) {
    UpdateMigrationAgent *agent =
            [[UpdateMigrationAgent alloc] init];
    [FileUtils clearCacheDirectory];
    [[VersionAgent sharedInstance] saveAppVersion];
}

反汇编后:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
v6 = _objc_msgSend(&OBJC_CLASS___VersionAgent,
                   "sharedInstance");
v7 = objc_retainAutoreleasedReturnValue(v6);
v41 = _objc_msgSend(v7, "isUpgraded");
objc_release(v7);
if ( v41 )
{
    NSLog(CFSTR("app is upgraded"), v41);
    _objc_msgSend(&OBJC_CLASS___FileUtils,
                  "clearCacheDirectory");
    v8 = _objc_msgSend(&OBJC_CLASS___VersionAgent,
                       "sharedInstance");
    v9 = objc_retainAutoreleasedReturnValue(v8);
    _objc_msgSend(v9, "saveAppVersion");
    objc_release(v9);
}

反汇编的代码被获得后,由于软件内部逻辑相比汇编代码来说可读性高了很多。黑客可以用来制作软件的注册机,也可以更加方便地破解网络通讯协议,从而制作出机器人(僵尸)帐号。最极端的情况下,黑客可以将反汇编的代码稍加修改,植入木马,然后重新打包发布在一些越狱渠道上,这将对用户产生巨大的危害。

对于IDA这类工具,我们的应对措施就比较少了。除了可以用一些宏来简单混淆类名外,我们也可以将关键的逻辑用纯C实现。例如微信的iOS端的通讯底层,就是用C实现的。这样的方式除了能保证通讯协议安全外,也可以在iOS和Android等多个平台使用同一套底层通讯代码,达到复用的目的。

总结

由于移动互联网的快速发展,人们的购物、理财等需求也在移动端出现,这使得移动应用的安全性越来越重要。由于部署在用户终端上,移动应用比服务器应用更容易被攻击,大家也需要在移动应用的网络通讯、本地文件和数据、源代码三方面做好防范,只有这样才能保证应用的安全。

版权说明

本文已发表在《程序员》杂志2014年5月刊上,链接为:http://www.csdn.net/article/2014-04-30/2819573-The-Secret-Of-App-Dev-Security

Posted by唐巧May 8th, 2014iOS

原创文章,版权声明:自由转载-非商用-非衍生-保持署名 |Creative Commons BY-NC-ND 3.0

发表评论

关闭菜单