# 點擊劫持防御備忘單
> 原文:[Clickjacking Defense Cheat Sheet](https://www.owasp.org/index.php/Clickjacking_Defense_Cheat_Sheet)
> 來源:[點擊劫持防御備忘單](http://cheatsheets.hackdig.com/?1.htm)
此備忘單的主要目的是為開發者提供點擊劫持/UI糾正攻擊的防御指導。
抵御“點擊劫持”攻擊的最普遍的方法是通過各種形式的“嵌入阻斷”功能,防止攻擊者通過iframe將你的站點嵌入他們的頁面。本備忘單將討論實現嵌入阻斷的兩種方式:第一種是X-Frame-Options頭信息(可能有些瀏覽器不支持);第二種方式是使用javascript編寫嵌入阻斷代碼。
## 使用X-Frame-Options 響應頭信息來防御
X-Frame-Options HTTP響應頭能用來向瀏覽器指明是否允許渲染在<frame>或<frame>標簽內的頁面。網站可以用它來確保網站內容不被嵌入到其他站點,從而避免遭受點擊劫持攻擊。
## X-Frame-Options響應頭類型
X-Frame-Options頭信息有三種可用的值
* **DENY**,阻止所有的域名嵌入此頁面。.
* **SAMEORIGIN**,只允許當前站點嵌入此頁面。
* **ALLOW-FROM uri**,允許指定的“URI”嵌入此頁面(如ALLOW-FROM http://www.example.com ,則允許www.example.com嵌入此頁面)。ALLOW-FROM選項是2012年左右添加的, 所以一些舊瀏覽器可能不支持這個參數。**不要依賴ALLOW-FROM參數。**如果你使用這個選項,但是瀏覽器不支持它,那相當于你沒有做任何點擊劫持防御。
## 瀏覽器支持
下面的瀏覽器支持X-Frame-Options頭信息。
| **瀏覽器** | **引入DENY/SAMEORIGIN支持** | **引入ALLOW-FROM支持** |
| --- | --- | --- |
| Chrome | 4.1.249.1042 | |
| Firefox (Gecko) | 3.6.9 (1.9.2.9) | 18.0 |
| Internet Explorer | 8.0 | 9.0 |
| Opera | 10.50 | |
| Safari | 4.0 | Not supported/Bug reported |
引用:
Mozilla Developer Network
IETF Draft
X-Frame-Options Compatibility Test - 從這個頁面可以獲得瀏覽器X-Frame-Options頭信息的支持情況
## 實現
要實現這種保護,你需要在想要保護(免受點擊劫持攻擊)的頁面上加上頭信息。一種方法是在每個頁面上都加上這種頭信息。另一種更簡單的方法是實現一個過濾器,自動的為每一個頁面添加頭信息。
OWASP有篇文章和一些代碼,提供了在Java EE環境中,有關防護方法的詳細實現。SDL博客發表了一篇文章,設計了在.NET環境下實現防護的方式。
## 局限
## 每個頁面的政策規范Per-page policy specification
如果每個頁面都需要指定政策,那么部署會變得非常復雜。為整個網站提供約束能力(如在登陸的時候)能夠簡化實現的過程。The policy needs to be specified for every page, which can complicate deployment. Providing the ability to enforce it for the entire site, at login time for instance, could simplify adoption.
## 多域名網站的問題Problems with multi-domain sites
當前的實現不允許網站管理員提供允許嵌入本頁面的域名白名單。雖然白名單列表是危險的,在一些特殊情況下,網站管理員可能除了使用多個主機名外,沒有其他選擇。The current implementation does not allow the webmaster to provide a whitelist of domains that are allowed to frame the page. While whitelisting can be dangerous, in some cases a webmaster might have no choice but to use more than one hostname.
## 代理
Web代理會添加或去掉頭信息。如果一個web代理去掉X-Frame-Options頭信息,網站將失去這種嵌入保護。
腳本是支持遺留瀏覽器防止被嵌入的最好解決方案
一種抵御點擊劫持的方法是在每個不允許被嵌入的頁面包含“frame-breaker”腳本。下面的方法能防止一個網頁被嵌入(甚至在不支持X-Frame-Options-Header的遺留瀏覽器上)。
在文檔的頭部添加下面的內容:
首先在樣式元素上添加一個ID:
```
<style id="antiClickjack">body{display:none !important;}</style>
```
然后在后面的腳本中根據這個ID刪除這個樣式:
```
<script type="text/javascript">
if (self === top) {
var antiClickjack = document.getElementById("antiClickjack");
antiClickjack.parentNode.removeChild(antiClickjack);
} else {
top.location = self.location;
}
</script>
```
這樣,一切都可以放在文檔的頭部,而你的API只需要一個method/taglib。
引用:https://www.codemagi.com/blog/post/194
## window.confirm() 保護
使用x-frame-options或frame-brreaking腳本是更萬無一失的保護方法。然而,在內容比如允許嵌入的情況下,可以使用window.confirm(),在用戶執行的操作時,通知用戶,從而減輕點擊劫持的危害。
調用window.confirm()會顯示一個不能被其他頁面嵌入的提示框。如果window.confirm()的發起頁面與父頁面不同,提示框將顯示在window.confirm()的源頁面。在這種情況下,瀏覽器顯示提示框的發起地址,從而避免用戶遭受點擊劫持攻擊。應該指出的是,IE瀏覽器是唯一不顯示提示框發起地址的瀏覽器,為了解決這個問題,要確保IE消息對話框內的信息包含操作類型的上下文信息。例如:
```
<script type="text/javascript">
var action_confirm = window.confirm("Are you sure you want to delete your youtube account?")
if (action_confirm) {
//... perform action
} else {
//... The user does not want to perform the requested action.
}
</script>
```
## 腳本失效
請看下面的代碼片段,用它來防御點擊劫持是**不推薦的**:
```
<script>if (top!=self) top.location.href=self.location.href</script>
```
這個簡單的框架打斷腳本試圖阻止頁面被框架包含,或者強制父窗口加載當前頁面的URL地址。不幸的是,許多反制這種類型的防御方法的腳本已經公開。我們在這里介紹一下。
## 雙層嵌入
一些框架防御技術通過在parent.location上分配值,使頁面跳轉到正確站點。如果受攻擊頁面只是被一個頁面嵌套,這種方法是可行的。然而,如果攻擊者將受攻擊頁面嵌入到一個被另一個頁面嵌入的頁面(一個雙層嵌入頁面),訪問parent.location就會違反現有流行的瀏覽器的安全規則(子框架導航規則)。這個安全規則會使這種跳轉失效:
**受攻擊頁面的防御代碼:**
```
if(top.location!=self.locaton) {
parent.location = self.location;
}
```
**攻擊者頂層嵌套頁面代碼:**
```
<iframe src="attacker2.html">
```
**攻擊者子嵌套頁面代碼:**
```
<iframe src="http://www.victim.com">
```
## onBeforeUnload事件
用戶可以手動取消任何框架頁面的跳轉請求。嵌套頁面利用這一點,注冊一個當框架頁面即將跳轉時執行的onBeforeUnload事件。這個事件函數會給用戶彈出一個提示框。比如攻擊者想嵌入PayPal的頁面,他注冊了一個事件,提示“你想退出PayPal嗎”。當這個提示框顯示給用戶時,用戶如果點擊取消,PayPal的頁面防御就會失效。
攻擊者使用下面的代碼來在父層頁面注冊一個unload事件:
```
<script>
window.onbeforeunload = function()
{
return "Asking the user nicely";
}
</script>
<iframe src="http://www.paypal.com">
```
PayPal的框架保護代碼將會生成一個BeforeUnload事件,從而激活我們的函數,提示用戶取消這次跳轉事件。
## 無內容沖洗
上一個攻擊需要用戶“參與”,同樣的攻擊也可以在不提示用戶的情況下發生。大多數瀏覽器(IE7, IE8, Google Chrome, and Firefox)讓攻擊者在onBeforeUnload事件中通過重復提交跳轉請求到一個返回空內容的頁面(HTTP/1.0 204 No Content)。請求一個無內容頁面是一個NOP,會刷新請求管道,從而取消原來的跳轉。下面是示例代碼(**經測試最新的chrome、firefox、safari已經不支持這個特性**):
```
var preventbust = 0
window.onbeforeunload = function() { killbust++ }
setInterval( function() {
if(killbust > 0){
killbust = 2;
window.top.location = 'http://nocontent204.com'
}
}, 1);
<iframe src="http://www.victim.com">
```
## 利用XSS過濾器
IE8和Google Chrome引入反射性XSS過濾器,這有助于保護web頁面免遭某些類型的XSS攻擊。Nava和Lindsay(供職于Blackhat公司)觀察到這些過濾器能被用來繞過框架保護代碼。IE8的XSS過濾器使用一組正則表達式來比較請求的參數,以此來找到特定的XSS攻擊。使用“假性誘導技術”,過濾器能被用來禁止某些的腳本。通過匹配請求參數中的所有腳本標簽的開頭,XSS過濾器會禁用頁面內所有內聯腳本,包括框架保護腳本。對于外部腳本也可以使用同樣的手法來禁用所有外部腳本。因為加載的javascript還可以調用、cookie也可用,這種攻擊對點擊劫持十分有效。
**被攻擊頁面的防護代碼**
```
<script>
if(top != self) {
top.location = self.location;
}
</script>
```
**攻擊頁面代碼:**
```
<iframe src="http://www.victim.com/?v=<script>if''>
```
XSS過濾器將匹配受攻擊頁面的參數`<script>if`,從而禁用受害者頁面所有的內聯腳本,包括框架保護代碼。
## Clobbering top.location
一些現代瀏覽器將location變量當成一個特殊的不可變上下文屬性。然而,在IE7和Safari4.0.4中,location變量能被重新定義。在IE7中,一旦框架頁面重新定義location變量,所有的子頁面的嘗試讀取top.location的框架保護代碼都會觸發一個安全規則(在另一個領域讀取局部變量),同樣,任何通過top.location改變父頁面的地址的操作都會失敗。
**被攻擊頁面的防護代碼:**
```
if(top.location != self.location) {
top.location = self.location;
}
```
**攻擊頁面代碼:**
```
<script> var location = "clobbered";
</script>
<iframe src="http://www.victim.com">
</iframe>
```
**Safari 4.0.4**
我們觀察到:雖然location在多數情況下是不變的,但當使用defineSetter設置一個自定義的location設置時,location會變為未定義變量。代碼如下:
```
<script>
window.defineSetter("location" , function(){});
</script>
```
這樣一來,任何嘗試讀取或改變父頁面的位置的操作都會失敗。
## 限制區域
大多數框架防護依賴被嵌套頁面內的Javascript,由它進行檢測和保護。如果javascript在子框架內被禁用,框架保護代碼將不會執行。不幸的是,有一些方法可以在子框架內限制javascript的運行:
**在IE 8:**
```
<iframe src="http://www.victim.com" security="restricted"></iframe>
```
**在Chrome:**
```
<iframe src="http://www.victim.com" sandbox></iframe>
```
**在Firefox和IE:** 在父頁面激活編輯模式。