點擊劫持會誘導你按下藏在可見頁面下方的另一個頁面的按鈕。本文講解其原理與可靠的防禦方法(不公開攻擊步驟)。
什麼會被盯上
「一鍵即可完成、而且有價值的操作」是攻擊目標。
| 容易被盯上的操作 | 為什麼會被盯上 |
|---|---|
| 轉帳、購買的確認 | 一鍵即可讓金錢發生流動 |
| 修改設定(可見範圍、授權許可) | 之後會導致帳號被接管或資訊被取得 |
| OAuth/權限的「允許」按鈕 | 被擅自批准帳號關聯授權 |
| 社群媒體的追蹤、按讚、發文 | 被濫用於擅自傳播、刷讚 |
為什麼會成立(原理)
瀏覽器可以用 iframe 載入另一個網站並疊加顯示。攻擊者把這個 iframe 設為透明(不透明度為 0),使用者看到的只有放在下方的假 UI。使用者按下「假按鈕」時,從座標上看,正疊加在其上方的真實按鈕就被按下了。
它與 CSRF 相似,但 CSRF 是「在背後傳送請求」,而點擊劫持是讓本人去操作真實的畫面,因此僅靠一次性權杖等 CSRF 對策無法防禦。
實際案例:瀏覽器外掛程式的權限對話框(2008)
2008 年 10 月,Adobe 針對一個影響多種瀏覽器的點擊劫持問題,發布了安全公告(APSA08-08)。根據媒體報導,網站可以把 Flash Player 的設定對話框隱形疊加,讓使用者在不知不覺中授予網站使用攝影機與麥克風的權限。Adobe 發布了修正版的 Flash Player,並作為暫時的因應方式,建議使用者在設定管理員中選擇「永遠拒絕」。
教訓是:被盯上的不只是轉帳按鈕。任何只要點一下就交出權限的畫面(「允許」「同意」「連結」)都在範圍內。MITRE 把這個弱點分類為 CWE-1021(Improper Restriction of Rendered UI Layers or Frames)。
防禦:不讓他站嵌入自己的網站
設定 CSP frame-ancestors(最優先)
在回應標頭中加入 Content-Security-Policy: frame-ancestors 'self'(僅允許自己的網站框架化)。如果不需要讓第三方嵌入,用 'none' 最安全。只有在確有需要允許的對象時才逐一列出網域。
同時使用 X-Frame-Options(向後相容)
為了照顧老舊環境,也加上 X-Frame-Options: DENY(或 SAMEORIGIN)。這樣新舊瀏覽器都能涵蓋。
對重要操作加上確認步驟
轉帳、授予權限等致命操作,要插入二次認證、確認對話框、操作前的意圖確認。這樣透明疊加就更難突破。
把工作階段 Cookie 設為 SameSite
用 SameSite=Lax/Strict 抑制來自其他網站的自動傳送。它對點擊劫持本身並非萬能,但能削弱相關的各類「源自他站的操作」。
X-Frame-Options 與 CSP frame-ancestors 的區別
兩個標頭都能阻止他站嵌入你的網站,但細節不同。
| X-Frame-Options | CSP frame-ancestors | |
|---|---|---|
| 值 | DENY(全部禁止)/ SAMEORIGIN(僅限同源) | 'none' / 'self' / 允許的網域清單 |
| 允許多個嵌入者 | 不行(ALLOW-FROM 在現代瀏覽器中無效) | 可以 |
| 用 meta 標籤設定 | 沒有效果 | 沒有效果 |
| 兩者同時存在時 | 支援的瀏覽器會忽略它 | 優先套用 |
| 角色 | 給舊瀏覽器的備援 | 現在的主要防禦 |
兩者都送出時,請讓意思一致:frame-ancestors 'none' 配 DENY,frame-ancestors 'self' 配 SAMEORIGIN。
常見的設定錯誤
- 以為 CSP 的
default-src會涵蓋它。frame-ancestors不會退回使用default-src。即使設了default-src 'none',只要沒寫frame-ancestors,嵌入仍然是允許的 - 寫在 meta 標籤裡:
<meta http-equiv>在這裡沒有效果,請以回應標頭送出 - 停留在
Content-Security-Policy-Report-Only:它只會回報違規,不會阻止嵌入。確認運作正常後,請改用強制執行的標頭 - 只在部分頁面設定:常見的情況是檢查了首頁,卻漏了登入頁、設定頁或錯誤頁。也請確認 CDN 或代理沒有把標頭拿掉
如何檢查自己的網站
用標頭檢測工具確認
在安全標頭檢查中輸入你網站的 URL,確認是否回傳 X-Frame-Options 與 CSP 的 frame-ancestors。不只檢查首頁,也要檢查登入後的設定頁,以及轉帳或授予權限的頁面。
用瀏覽器的開發者工具確認
開啟「網路」分頁並重新載入頁面,查看 HTML 回應的標頭。也確認標頭沒有被重複送出,或送出互相矛盾的值。
在一個地方設定
在一個地方(nginx 或 Caddy 等 Web 伺服器、反向代理,或框架)對所有回應加上它,就能同時避免遺漏與重複。如果要寫新的 CSP,CSP 產生器可以組出包含 frame-ancestors 的設定。
本站的觀點:一行回應標頭最有效,先檢查自己的網站
點擊劫持的對策不是複雜的程式碼,而是用一到兩行回應標頭禁止嵌入。在框架或反向代理(Caddy/nginx)上對所有頁面統一加上,杜絕遺漏。最常見的失誤,是自以為已經設定好、實際上卻漏掉的標頭,所以設定之後,請用上面的步驟確認它真的有被回傳。
出處(一手資料)
- OWASP「Clickjacking Defense Cheat Sheet」— cheatsheetseries.owasp.org(frame-ancestors、X-Frame-Options、SameSite;ALLOW-FROM 已失效;meta 標籤沒有效果;frame busting 的限制)
- MDN「CSP: frame-ancestors」— developer.mozilla.org(可用的值、不退回 default-src、meta 不支援)
- RFC 7034「HTTP Header Field X-Frame-Options」— rfc-editor.org
- IPA「安全なウェブサイトの作り方 1.9 クリックジャッキング」(日文)— ipa.go.jp
- Adobe「Security Advisory for Flash Player (APSA08-08)」(2008 年 10 月 7 日)— adobe.com
- Computerworld「Clickjackers could hijack webcams, microphones, Adobe warns」(2008 年 10 月)— computerworld.com(攝影機與麥克風的權限對話框是攻擊目標)
- MITRE「CWE-1021: Improper Restriction of Rendered UI Layers or Frames」— cwe.mitre.org
接下來閱讀
- 術語:什麼是 CSRF / 什麼是 XSS
- 指南:安全標頭的選擇(仍然需要的與已過時的)
- 檢查:安全標頭檢查 / CSP 產生器