「我以為按下的是這個按鈕,實際卻是背後另一個頁面的按鈕」——這就是點擊劫持。本文講解其原理與可靠的防禦方法(不公開攻擊步驟)。
什麼會被盯上
「一鍵即可完成、而且有價值的操作」是攻擊目標。
| 容易被盯上的操作 | 為什麼會被盯上 |
|---|---|
| 轉帳、購買的確認 | 一鍵即可讓金錢發生流動 |
| 修改設定(可見範圍、授權許可) | 之後會導致帳號被接管或資訊被取得 |
| OAuth/權限的「允許」按鈕 | 被擅自批准帳號關聯授權 |
| 社群媒體的追蹤、按讚、發文 | 被濫用於擅自傳播、刷讚 |
為什麼會成立(原理)
瀏覽器可以用 iframe 載入另一個網站並疊加顯示。攻擊者把這個 iframe 設為透明(不透明度為 0),使用者看到的只有放在下方的假 UI。使用者按下「假按鈕」時,從座標上看,正疊加在其上方的真實按鈕就被按下了。
它與 CSRF 相似,但 CSRF 是「在背後傳送請求」,而點擊劫持是讓本人去操作真實的畫面,因此僅靠一次性權杖等 CSRF 對策無法防禦。
防禦:核心是「不讓被嵌入」
設定 CSP frame-ancestors(最優先)
在回應標頭中加入 Content-Security-Policy: frame-ancestors 'self'(僅允許自己的網站框架化)。如果不需要讓第三方嵌入,用 'none' 最安全。只有在確有需要允許的對象時才逐一列出網域。
同時使用 X-Frame-Options(向後相容)
為了照顧老舊環境,也加上 X-Frame-Options: DENY(或 SAMEORIGIN)。這是兼顧新舊瀏覽器的多層防禦。
對重要操作要求「再加一道」
轉帳、授予權限等致命操作,要插入二次認證、確認對話框、操作前的意圖確認。這樣透明疊加就更難突破。
把工作階段 Cookie 設為 SameSite
用 SameSite=Lax/Strict 抑制來自其他網站的自動傳送。它對點擊劫持本身並非萬能,但能削弱相關的各類「源自他站的操作」。
本站的觀點:一行回應標頭最有效。先來測自己的網站
點擊劫持的對策不是花俏的程式碼,而是用一到兩行回應標頭奪走其疊加基礎,這是最短路徑。在框架或反向代理(Caddy/nginx)上對所有頁面統一加上,杜絕遺漏,才是實戰做法。你的網站上 frame-ancestors 是否生效,可以用本站的工具中的安全回應標頭診斷來確認。「自以為已經設定好了」其實卻漏掉了,才是最常見的事故。
接下來閱讀
FAQ
Q點擊劫持會讓人遭受什麼?
使用者「自以為」按下的點擊,實際落在了疊加於背後那個真實頁面的按鈕上。一鍵轉帳、修改設定、授予權限、在社群媒體上追蹤/按讚、同意按鈕等「一鍵即可完成的重要操作」都會被濫用。它的特點不是竊取密碼,而是讓已登入的使用者本人去執行操作。
Q最有效的防禦是什麼?
就是「不讓自己的網站被嵌入到他站的框架(iframe)裡」。在回應標頭中把 CSP 的 frame-ancestors 設為 'self'(或僅允許指定網域),並為了向後相容同時使用 X-Frame-Options: DENY。這樣就能直接奪走可供疊加的基礎。
Q只靠 JavaScript 的 frame busting(跳出框架)夠嗎?
不夠。舊式的「如果發現自己在 iframe 內就跳出去」的 JS 有很多繞過手法,且在 JS 被停用時無法防護。核心做法是用伺服器端的回應標頭(frame-ancestors / X-Frame-Options),讓瀏覽器直接拒絕被嵌入。