Javascript 點(diǎn)擊劫持攻擊

2023-02-17 10:56 更新

“點(diǎn)擊劫持”攻擊允許惡意頁(yè)面 以用戶的名義 點(diǎn)擊“受害網(wǎng)站”。

許多網(wǎng)站都被黑客以這種方式攻擊過(guò),包括 Twitter、Facebook 和 Paypal 等許多網(wǎng)站。當(dāng)然,它們都已經(jīng)被修復(fù)了。

原理

原理十分簡(jiǎn)單。

我們以 Facebook 為例,解釋點(diǎn)擊劫持是如何完成的:

  1. 訪問(wèn)者被惡意頁(yè)面吸引。怎樣吸引的不重要。
  2. 頁(yè)面上有一個(gè)看起來(lái)無(wú)害的鏈接(例如:“變得富有”或者“點(diǎn)我,超好玩!”)。
  3. 惡意頁(yè)面在該鏈接上方放置了一個(gè)透明的 ?<iframe>?,其 ?src? 來(lái)自于 facebook.com,這使得“點(diǎn)贊”按鈕恰好位于該鏈接上面。這通常是通過(guò) ?z-index? 實(shí)現(xiàn)的。
  4. 用戶嘗試點(diǎn)擊該鏈接時(shí),實(shí)際上點(diǎn)擊的是“點(diǎn)贊”按鈕。

示例

這是惡意頁(yè)面看起來(lái)的樣子。為了清楚起見(jiàn),我們將 <iframe> 設(shè)置成了半透明的(在真正的惡意頁(yè)面中,它是全透明的):

<style>
iframe { /* 來(lái)自受害網(wǎng)站的 iframe */
  width: 400px;
  height: 100px;
  position: absolute;
  top:0; left:-20px;
  opacity: 0.5; /* 在實(shí)際中為 opacity:0 */
  z-index: 1;
}
</style>

<div>點(diǎn)擊即可變得富有:</div>

<!-- 來(lái)自受害網(wǎng)站的 url -->
<iframe src="/clickjacking/facebook.html"></iframe>

<button>點(diǎn)這里!</button>

<div>……你很酷(我實(shí)際上是一名帥氣的黑客)!</div>

完整示例

在上面這個(gè)示例中,我們有一個(gè)半透明的 <iframe src="facebook.html">,我們可以看到,它位于按鈕之上。點(diǎn)擊按鈕實(shí)際上會(huì)點(diǎn)擊在 iframe 上,但這對(duì)用戶不可見(jiàn),因?yàn)?iframe 是透明的。

結(jié)果,如果訪問(wèn)者登陸了 Facebook(“記住我”通常是打開的),那么這個(gè)行為就會(huì)點(diǎn)一個(gè)“贊”。Twitter 上是 “Follow” 按鈕。

下面是相同的示例,但 iframe 的透明度設(shè)置為了 opacity:0,更符合實(shí)際情況:

示例

我們進(jìn)行攻擊所需要做的 —— 就是將 <iframe> 放置在惡意頁(yè)面中,使得按鈕恰好位于鏈接的正上方。這樣當(dāng)用戶點(diǎn)擊鏈接時(shí),他們實(shí)際上點(diǎn)擊的是按鈕。這通??梢酝ㄟ^(guò) CSS 實(shí)現(xiàn)。

點(diǎn)擊劫持是對(duì)點(diǎn)擊事件,而非鍵盤事件

此攻擊僅影響鼠標(biāo)行為(或者類似的行為,例如在手機(jī)上的點(diǎn)擊)。

鍵盤輸入很難重定向。從技術(shù)上講,我們可以用 iframe 的文本區(qū)域覆蓋原有的文本區(qū)域?qū)崿F(xiàn)攻擊。因此,當(dāng)訪問(wèn)者試圖聚焦頁(yè)面中的輸入時(shí),實(shí)際上聚焦的是 iframe 中的輸入。

但是這里有個(gè)問(wèn)題。訪問(wèn)者鍵入的所有內(nèi)容都會(huì)被隱藏,因?yàn)樵?iframe 是不可見(jiàn)的。

當(dāng)用戶無(wú)法在屏幕上看到自己輸入的字符時(shí),通常會(huì)停止打字。

傳統(tǒng)防御(弱 ??)

最古老的防御措施是一段用于禁止在 frame 中打開頁(yè)面的 JavaScript 代碼(所謂的 “framebusting”)。

它看起來(lái)像這樣:

if (top != window) {
  top.location = window.location;
}

意思是說(shuō):如果 window 發(fā)現(xiàn)它不在頂部,那么它將自動(dòng)使其自身位于頂部。

這個(gè)方法并不可靠,因?yàn)橛性S多方式可以繞過(guò)這個(gè)限制。下面我們就介紹幾個(gè)。

阻止頂級(jí)導(dǎo)航

我們可以阻止因更改 beforeunload 事件處理程序中的 top.location 而引起的過(guò)渡(transition)。

頂級(jí)頁(yè)面(從屬于黑客)在 beforeunload 上設(shè)置了一個(gè)用于阻止的處理程序,像這樣:

window.onbeforeunload = function() {
  return false;
};

當(dāng) iframe 試圖更改 top.location 時(shí),訪問(wèn)者會(huì)收到一條消息,詢問(wèn)他們是否要離開頁(yè)面。

在大多數(shù)情況下,訪問(wèn)者會(huì)做出否定的回答,因?yàn)樗麄儾⒉恢肋€有這么一個(gè) iframe,他們所看到的只有頂級(jí)頁(yè)面,他們沒(méi)有理由離開。所以 top.location 不會(huì)變化!

演示示例

Sandbox 特性

sandbox 特性的限制之一就是導(dǎo)航。沙箱化的 iframe 不能更改 top.location。

但我們可以添加具有 sandbox="allow-scripts allow-forms" 的 iframe。從而放開限制,允許腳本和表單。但我們沒(méi)添加 allow-top-navigation,因此更改 top.location 是被禁止的。

代碼如下:

<iframe sandbox="allow-scripts allow-forms" src="facebook.html"></iframe>

還有其他方式可以繞過(guò)這個(gè)弱雞防御。

X-Frame-Options

服務(wù)器端 header X-Frame-Options 可以允許或禁止在 frame 中顯示頁(yè)面。

它必須被完全作為 HTTP-header 發(fā)送:如果瀏覽器在 HTML <meta> 標(biāo)簽中找到它,則會(huì)忽略它。因此,<meta http-equiv="X-Frame-Options"...> 沒(méi)有任何作用。

這個(gè) header 可能包含 3 個(gè)值:

?DENY ?

始終禁止在 frame 中顯示此頁(yè)面。

?SAMEORIGIN ?

允許在和父文檔同源的 frame 中顯示此頁(yè)面。

?ALLOW-FROM domain ?

允許在來(lái)自給定域的父文檔的 frame 中顯示此頁(yè)面。

例如,Twitter 使用的是 X-Frame-Options: SAMEORIGIN。

結(jié)果如下:

<iframe src="https://twitter.com" rel="external nofollow" ></iframe>

上面這個(gè) iframe 可能為空,或者通過(guò) alert 告知你瀏覽器不允許以這種方式導(dǎo)航至該頁(yè)面,這取決于你的瀏覽器。

顯示禁用的功能

X-Frame-Options 有一個(gè)副作用。其他的網(wǎng)站即使有充分的理由也無(wú)法在 frame 中顯示我們的頁(yè)面。

因此,還有其他解決方案……例如,我們可以用一個(gè)樣式為 height: 100%; width: 100%; 的 <div> “覆蓋”頁(yè)面,這樣它就能攔截所有點(diǎn)擊。如果 window == top 或者我們確定不需要保護(hù)時(shí),再將該 <div> 移除。

像這樣:

<style>
  #protector {
    height: 100%;
    width: 100%;
    position: absolute;
    left: 0;
    top: 0;
    z-index: 99999999;
  }
</style>

<div id="protector">
  <a href="/" target="_blank">前往網(wǎng)站</a>
</div>

<script>
  // 如果頂級(jí)窗口來(lái)自其他源,這里則會(huì)出現(xiàn)一個(gè) error
  // 但是在本例中沒(méi)有問(wèn)題
  if (top.document.domain == document.domain) {
    protector.remove();
  }
</script>

示例

Samesite cookie 特性

samesite cookie 特性也可以阻止點(diǎn)擊劫持攻擊。

具有 samesite 特性的 cookie 僅在網(wǎng)站是通過(guò)直接方式打開(而不是通過(guò) frame 或其他方式)的情況下才發(fā)送到網(wǎng)站。更多細(xì)節(jié)請(qǐng)見(jiàn) Cookie,document.cookie。

如果網(wǎng)站,例如 Facebook,在其身份驗(yàn)證 cookie 中具有 samesite 特性,像這樣:

Set-Cookie: authorization=secret; samesite

……那么,當(dāng)在另一個(gè)網(wǎng)站中的 iframe 中打開 Facebook 時(shí),此類 cookie 將不會(huì)被發(fā)送。因此,攻擊將失敗。

當(dāng)不使用 cookie 時(shí),samesite cookie 特性將不會(huì)有任何影響。這可以使其他網(wǎng)站能夠輕松地在 iframe 中顯示我們公開的、未進(jìn)行身份驗(yàn)證的頁(yè)面。

然而,這也可能會(huì)使得劫持攻擊在少數(shù)情況下起作用。例如,通過(guò)檢查 IP 地址來(lái)防止重復(fù)投票的匿名投票網(wǎng)站仍然會(huì)受到點(diǎn)擊劫持的攻擊,因?yàn)樗皇褂?cookie 對(duì)用戶身份進(jìn)行驗(yàn)證。

總結(jié)

點(diǎn)擊劫持是一種“誘騙”用戶在不知情的情況下點(diǎn)擊惡意網(wǎng)站的方式。如果是重要的點(diǎn)擊操作,這是非常危險(xiǎn)的。

黑客可以通過(guò)信息發(fā)布指向他的惡意頁(yè)面的鏈接,或者通過(guò)某些手段引誘訪問(wèn)者訪問(wèn)他的頁(yè)面。當(dāng)然還有很多其他變體。

一方面 —— 這種攻擊方式是“淺層”的:黑客所做的只是攔截一次點(diǎn)擊。但另一方面,如果黑客知道在點(diǎn)擊之后將出現(xiàn)另一個(gè)控件,則他們可能還會(huì)使用狡猾的消息來(lái)迫使用戶也點(diǎn)擊它們。

這種攻擊相當(dāng)危險(xiǎn),因?yàn)樵谠O(shè)計(jì)交互界面時(shí),我們通常不會(huì)考慮到可能會(huì)有黑客代表用戶點(diǎn)擊界面。所以,在許多意想不到的地方可能發(fā)現(xiàn)攻擊漏洞。

  • 建議在那些不希望被在 frame 中查看的頁(yè)面上(或整個(gè)網(wǎng)站上)使用 ?X-Frame-Options: SAMEORIGIN?。
  • 如果我們希望允許在 frame 中顯示我們的頁(yè)面,那我們使用一個(gè) ?<div>? 對(duì)整個(gè)頁(yè)面進(jìn)行遮蓋,這樣也是安全的。


以上內(nèi)容是否對(duì)您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)