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

2023-02-17 10:56 更新

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

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

原理

原理十分簡單。

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

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

示例

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

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

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

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

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

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

完整示例

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

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

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

示例

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

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

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

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

但是這里有個問題。訪問者鍵入的所有內(nèi)容都會被隱藏,因為該 iframe 是不可見的。

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

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

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

它看起來像這樣:

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

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

這個方法并不可靠,因為有許多方式可以繞過這個限制。下面我們就介紹幾個。

阻止頂級導(dǎo)航

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

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

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

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

在大多數(shù)情況下,訪問者會做出否定的回答,因為他們并不知道還有這么一個 iframe,他們所看到的只有頂級頁面,他們沒有理由離開。所以 top.location 不會變化!

演示示例

Sandbox 特性

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

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

代碼如下:

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

還有其他方式可以繞過這個弱雞防御。

X-Frame-Options

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

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

這個 header 可能包含 3 個值:

?DENY ?

始終禁止在 frame 中顯示此頁面。

?SAMEORIGIN ?

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

?ALLOW-FROM domain ?

允許在來自給定域的父文檔的 frame 中顯示此頁面。

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

結(jié)果如下:

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

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

顯示禁用的功能

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

因此,還有其他解決方案……例如,我們可以用一個樣式為 height: 100%; width: 100%; 的 <div> “覆蓋”頁面,這樣它就能攔截所有點(diǎn)擊。如果 window == top 或者我們確定不需要保護(hù)時,再將該 <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>
  // 如果頂級窗口來自其他源,這里則會出現(xiàn)一個 error
  // 但是在本例中沒有問題
  if (top.document.domain == document.domain) {
    protector.remove();
  }
</script>

示例

Samesite cookie 特性

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

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

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

Set-Cookie: authorization=secret; samesite

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

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

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

總結(jié)

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

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

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

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

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


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

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號