今天,我们跟大家聊聊Web应用的客户端安全的故事。这个故事讲述的是攻击者如何从Web应用的客户端下手发动攻击的战术。这是一种非常简单却又令人胆寒的战术:之所以说它令人胆寒是因为攻击者能给其它的用户施展摄魂大法,让他们梦游般的去做一些他们不想做的事情;之所以说它简单,是因为攻击者要想达到上述目的,只需向用户发送一封电子邮件或设法让他们去一个web页面就足够了。有时候,人们将这个安全问题称为“客户端攻击”——可能是受到古代木马攻城故事的启发吧。不过即便你对这个遥远的故事不熟也不要紧,本文将向读者详细解释这个问题,并讨论可能解决。
一、Web应用客户端的木马攻城
介绍这个安全问题最好的方法就是进行实例分析。按照循序渐进的原则,我们首先介绍一个较为简单的例子,然后再讨论更为复杂的例子,如网络银行等(是的,网络银行也同样面临这种威胁)。我们首先考察的是一个假想的投票站点,该站点允许用户给不同的候选人投票,并统计出选举结果。用于投票的web页面可能包含下列HTML代码:
由于该表单使用的是GET方式,所以用户给他心仪的候选人投票时,将通过类似下面的URL来提交表单:
现在,攻击者会设法诱骗其他用户来点击这些链接,比如复制以上URL并通过电子邮件大量发送,并向收件人声称这些URL链接到一个能诱惑人的事物上,比如非常好玩的游戏、裸体美女、耸人听闻的报道、有趣的笑话,等等。事实上,我们几乎没有办法阻止他们这么做——诸位,有谁没收到过?!如果某些人点击了这些链接,那么他们就会给攻击者喜爱的候选人投上一票,这样的话,统计结果就有猫腻了。
也许您对这个例子持有异议。首先,您可能会说,大部分用户都不会点击这样的链接,因为这个链接看上去非常可疑。但是对攻击者来说这不是个问题,因为他们可以使用重定向技术来隐藏URL,从而迷惑更多的用户。他可以在邮件中使用不直接指向投票站点,而是指向其它页面的URL,比如使用一个指向他自己的的URL:
看到链接中“nicejoke”,您也许以为这是一个关于笑话的页面。实际上,与您所认为的正好相反,这个nicejoke.html页面中并没有任何笑话,而是包含下列HTML代码:
一旦读取meta标签,它就会被重定向至投票页面的URL,等用户明白过来是怎么回事的时候,已经为时完矣!当然,攻击者使用脚本或者HTTP的Location报头的话,也能达到同样的效果。
您对该示例持有疑议的第二个理由可能是:就本例而言,使用一个GET请求是错误的。根据定义HTTP的RFC 2616文档,当动作具有副作用(比如有安全隐患)的时候,应该使用POST请求。当使用POST后,就无法在一个URL中放入投票细节,因为POST请求中的参数被隐藏在请求本身之中。但是这并不能阻止攻击者的脚步——他们完全可以不去诱骗浏览器访问以上URL,而是欺骗受害者浏览一个自动提交的表单,例如下面的表单:
这个名为“f”的表单包含了一个隐藏字段,其中的参数“alt”已经被攻击者设为他们选定的值了。表单之下是JavaScript代码,它的作用实际上就是提交该表单,就像是用户按下了并不存在的提交按钮那样。
那些坏家伙可以将这些代码插入一个web页面,并哄骗用户访问它。这样一来,当受害者明白过来的时候,他们已经替别人投完票了。
更好的方法是将上述表单嵌入一封HTML编码的电子邮件中。一些流行的电子邮件客户端不仅能查看HTML邮件,甚至可以执行JavaScript代码。不幸的用户可能仅仅由于阅读攻击者的邮件而神不知鬼不觉地将它们的票投给了攻击者,如果邮件程序自动地预览来信的话,甚至根本都不需要阅读邮件。
请注意,公司的Outlook在显示HTML格式的电子邮件时会用到IE浏览器的组件。作者在Windows 2000上测试时发现,Outlook 使用的IE实例会跟已打开的IE共享一切,包括会话cookie。所以您一定要记住这一点,尤其是到后文的网络银行的时候,因为正是这一点为更酷的远程控制电子邮件铺平了道路。幸运的是,Windows XP默认时不会运行嵌入HTML格式电子邮件中的脚本——至少我测试的脚本没有被执行。
迄今为止,我们已经考察了一个用于投票的简单应用程序。但是,让人胆寒的客户端木马战还涉及到身份验证。因为这些特洛伊木马攻击是通过欺骗用户或者他的浏览器访问目标站点来运作的,所以只有用户业已登录到目标站点的时候,特洛伊木马才能以该用户的名义做各种事情。
假设一个用户已登录到他的网络银行,而这时一个攻击者想要冒充那个用户来发财的话,只要能欺骗用户浏览下列内容就足矣:
现在,如果受害者早已登录到银行,而该银行也接受此类表单,那么该用户就会在毫不知情的情况下把钱转到攻击者的帐户上,当然攻击者也可以利用此特权给别人栽赃。
要做到这一点,受害者必须已经登录到目标站点,否则攻击者也无可奈何。然而,如果用户选择了“记住密码”选项,那么他就会一直处于登录状态。如果目标站点是一个基于域认证(例如 IIS上的NTLM)的内部网的话,情况同样如此。幸运的是,银行之类的“严肃”站点却不会提供自动认证——攻击者也许以为这很“不幸”。
如果该用户没有总处于登录状态的话,那么攻击者就必须在诱骗用户浏览恶意的HTML之前,首先以某种方式设法让受害者先登录到目标站点。对于那些允许用户添加内容的站点(如论坛)来说,这可能很容易:只需添加一个非常诱人的声明来邀请人们查看一个链接即可。然而,很多情况下,攻击者是无法在目标站点上插入消息的,这样的话,他就不得不另外想辙了,这时,社交工程恐怕就能派上用场了!比方说,我们的目标站点是一个名为bank.example.com的银行,攻击者想要设法先让用户登录该银行,继而诱骗该用户浏览上面的转账表单。
为此,攻击者可以向受害者发送一封貌似来自该银行的电子邮件,如:
大多数用户会都认为其中这个URL指向的是该银行的,但事实并非如此。使用@符号后,这个URL实际上是命令浏览器以用户名bank.example.com连接到站点167772161。这个长整数167772161实际上就是攻击者的IP地址10.0.0.1,只不过现在已经编码为一个32位整数而已;而check.html则是一个包含HTML代码的页面,而这些HTML代码将自动提交转帐请求。受害者一旦上钩,攻击者就会发一笔横财。
对于一些银行,进行一次转帐需要两个步骤。首先,您要提供全部转帐细节:转出方帐户和转入方帐户,金额,支付日期等等,所有这些信息都被临时存放在该用户的会话session中。收集这些信息之后,银行还有一个确认的步骤,即要求用户验收这些交易细节。请不要认为这些银行在客户端木马战面前会比那些的银行更加安全一些。这些站点可能会像一步式的站点那样容易被骗:根据确认步骤的实现方式,设法让受害者浏览包含多个框架(frame)的站点,每个框架对应于一个步骤,如下所示:
文件info.html中有一个自动提交的填有交易细节的表单;而文件confirm.html则存放一个提交确认页面的脚本,但是要等待适当的延迟,以确保确认消息在info.html之后到达服务器。至于其他的,我想就没有必要再多说了吧。
无论攻击者选择什么方法,只要被害者看到由这次转帐引起的页面,就会引起他的怀疑。解决这个问题的方法是把这个页面嵌入一个小到不会引起人们注意的框架(frame)中,并在另外一个框架(frame)中放上一些伪造的信息。如果目标站点的某些地方没有进行HTML输出过滤的话,那么还有一个办法,那就是转帐一旦完成,就立即通过跨站脚本把浏览器重定向到另一个页面。