文章目录
  1. 1. 前言
  2. 2. 一、网络安全
    1. 2.1. 安全地传输用户密码
    2. 2.2. 防止通讯协议被轻易破解
    3. 2.3. 验证应用内支付的凭证
  3. 3. 二、本地文件和数据安全
    1. 3.1. 程序文件的安全
    2. 3.2. 本地数据安全
  4. 4. 三、源代码安全
  5. 5. 总结
  6. 6. 版权说明

【摘要】: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 文件的内容:

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 几乎还原了原本的逻辑,而且可读性也非常高。

原始代码:

if ([[VersionAgent sharedInstance] isUpgraded]) {
UpdateMigrationAgent *agent =
[[UpdateMigrationAgent alloc] init];
[FileUtils clearCacheDirectory];
[[VersionAgent sharedInstance] saveAppVersion];
}

反汇编后:

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