【前端安全】JavaScript防http劫持與XSS
作為前端,一直以來都知道HTTP劫持
與XSS跨站指令碼
(Cross-site scripting)、CSRF跨站請求偽造
(Cross-site request forgery)。但是一直都沒有深入研究過,前些日子同事的分享會偶然提及,我也對這一塊很感興趣,便深入研究了一番。
最近用 JavaScript 寫了一個元件,可以在前端層面防禦部分 HTTP 劫持與 XSS。
當然,防禦這些劫持最好的方法還是從後端入手,前端能做的實在太少。而且由於原始碼的暴露,攻擊者很容易繞過我們的防禦手段。但是這不代表我們去了解這塊的相關知識是沒意義的,本文的許多方法,用在其他方面也是大有作用。
已上傳到 Github – httphijack.js ,歡迎感興趣看看順手點個 star ,本文示例程式碼,防範方法在元件原始碼中皆可找到。
接下來進入正文。
HTTP劫持、DNS劫持與XSS
先簡單講講什麼是 HTTP 劫持與 DNS 劫持。
HTTP劫持
什麼是HTTP劫持呢,大多數情況是運營商HTTP劫持,當我們使用HTTP請求請求一個網站頁面的時候,網路運營商會在正常的資料流中插入精心設計的網路資料包文,讓客戶端(通常是瀏覽器)展示“錯誤”的資料,通常是一些彈窗,宣傳性廣告或者直接顯示某網站的內容,大家應該都有遇到過。
DNS劫持
DNS 劫持就是通過劫持了 DNS 伺服器,通過某些手段取得某域名的解析記錄控制權,進而修改此域名的解析結果,導致對該域名的訪問由原IP地址轉入到修改後的指定IP,其結果就是對特定的網址不能訪問或訪問的是假網址,從而實現竊取資料或者破壞原有正常服務的目的。
DNS 劫持比之 HTTP 劫持 更加過分,簡單說就是我們請求的是 http://www.a.com/index.html ,直接被重定向了 http://www.b.com/index.html ,本文不會過多討論這種情況。
XSS跨站指令碼
XSS指的是攻擊者利用漏洞,向 Web 頁面中注入惡意程式碼,當使用者瀏覽該頁之時,注入的程式碼會被執行,從而達到攻擊的特殊目的。
關於這些攻擊如何生成,攻擊者如何注入惡意程式碼到頁面中本文不做討論,只要知道如 HTTP 劫持 和 XSS 最終都是惡意程式碼在客戶端,通常也就是使用者瀏覽器端執行,本文將討論的就是假設注入已經存在,如何利用 Javascript 進行行之有效的前端防護。
頁面被嵌入 iframe 中,重定向 iframe
先來說說我們的頁面被嵌入了 iframe 的情況。也就是,網路運營商為了儘可能地減少植入廣告對原有網站頁面的影響,通常會通過把原有網站頁面放置到一個和原頁面相同大小的 iframe 裡面去,那麼就可以通過這個 iframe 來隔離廣告程式碼對原有頁面的影響。
這種情況還比較好處理,我們只需要知道我們的頁面是否被巢狀在 iframe 中,如果是,則重定向外層頁面到我們的正常頁面即可。
那麼有沒有方法知道我們的頁面當前存在於 iframe 中呢?有的,就是 window.self
與 window.top
。
window.self
返回一個指向當前 window 物件的引用。
window.top
返回視窗體系中的最頂層視窗的引用。
對於非同源的域名,iframe 子頁面無法通過 parent.location 或者 top.location 拿到具體的頁面地址,但是可以寫入 top.location ,也就是可以控制父頁面的跳轉。
兩個屬性分別可以又簡寫為 self 與 top,所以當發現我們的頁面被巢狀在 iframe 時,可以重定向父級頁面:
if (self != top) {
// 我們的正常頁面
var url = location.href;
// 父級頁面重定向
top.location = url;
}
使用白名單放行正常 iframe 巢狀
當然很多時候,也許運營需要,我們的頁面會被以各種方式推廣,也有可能是正常業務需要被巢狀在 iframe 中,這個時候我們需要一個白名單或者黑名單,當我們的頁面被巢狀在 iframe 中且父級頁面域名存在白名單中,則不做重定向操作。
上面也說了,使用 top.location.href 是沒辦法拿到父級頁面的 URL 的,這時候,需要使用document.referrer
。
通過 document.referrer 可以拿到跨域 iframe 父頁面的URL。
// 建立白名單
var whiteList = [
'www.aaa.com',
'res.bbb.com'
];
if (self != top) {
var
// 使用 document.referrer 可以拿到跨域 iframe 父頁面的 URL
parentUrl = document.referrer,
length = whiteList.length,
i = 0;
for(; i<length; i++){
// 建立白名單正則
var reg = new RegExp(whiteList[i],'i');
// 存在白名單中,放行
if(reg.test(parentUrl)){
return;
}
}
// 我們的正常頁面
var url = location.href;
// 父級頁面重定向
top.location = url;
}
更改 URL 引數繞過運營商標記
這樣就完了嗎?沒有,我們雖然重定向了父頁面,但是在重定向的過程中,既然第一次可以巢狀,那麼這一次重定向的過程中頁面也許又被 iframe 巢狀了,真尼瑪蛋疼。
當然運營商這種劫持通常也是有跡可循,最常規的手段是在頁面 URL 中設定一個引數,例如 http://www.example.com/index.html?iframe_hijack_redirected=1 ,其中 iframe_hijack_redirected=1
表示頁面已經被劫持過了,就不再巢狀 iframe 了。所以根據這個特性,我們可以改寫我們的 URL ,使之看上去已經被劫持了:
var flag = 'iframe_hijack_redirected';
// 當前頁面存在於一個 iframe 中
// 此處需要建立一個白名單匹配規則,白名單預設放行
if (self != top) {
var
// 使用 document.referrer 可以拿到跨域 iframe 父頁面的 URL
parentUrl = document.referrer,
length = whiteList.length,
i = 0;
for(; i<length; i++){
// 建立白名單正則
var reg = new RegExp(whiteList[i],'i');
// 存在白名單中,放行
if(reg.test(parentUrl)){
return;
}
}
var url = location.href;
var parts = url.split('#');
if (location.search) {
parts[0] += '&' + flag + '=1';
} else {
parts[0] += '?' + flag + '=1';
}
try {
console.log('頁面被嵌入iframe中:', url);
top.location.href = parts.join('#');
} catch (e) {}
}
當然,如果這個引數一改,防巢狀的程式碼就失效了。所以我們還需要建立一個上報系統,當發現頁面被巢狀時,傳送一個攔截上報,即便重定向失敗,也可以知道頁面嵌入 iframe 中的 URL,根據分析這些 URL ,不斷增強我們的防護手段,這個後文會提及。
內聯事件及內聯指令碼攔截
在 XSS 中,其實可以注入指令碼的方式非常的多,尤其是 HTML5 出來之後,一不留神,許多的新標籤都可以用於注入可執行指令碼。
列出一些比較常見的注入方式:
<a href="javascript:alert(1)" ></a>
<iframe src="javascript:alert(1)" />
<img src='x' onerror="alert(1)" />
<video src='x' onerror="alert(1)" ></video>
<div onclick="alert(1)" onmouseover="alert(2)" ><div>
除去一些未列出來的非常少見生僻的注入方式,大部分都是 javascript:...
及內聯事件 on*
。
我們假設注入已經發生,那麼有沒有辦法攔截這些內聯事件與內聯指令碼的執行呢?
對於上面列出的 (1) (5) ,這種需要使用者點選或者執行某種事件之後才執行的指令碼,我們是有辦法進行防禦的。
瀏覽器事件模型
這裡說能夠攔截,涉及到了事件模型
相關的原理。
我們都知道,標準瀏覽器事件模型存在三個階段:
- 捕獲階段
- 目標階段
- 冒泡階段
對於一個這樣 <a href="javascript:alert(222)" ></a>
的 a 標籤而言,真正觸發元素 alert(222)
是處於點選事件的目標階段。
<iframe src="http://codepen.io/Chokcoco/embed/EyrjkG/?height=265&theme-id=0&default-tab=html,result&embed-version=2" frameborder="no" scrolling="no" width="320" height="265" style="transition: all 0.3s; width: 917px !important;"></iframe>
點選上面的 click me
,先彈出 111 ,後彈出 222。
那麼,我們只需要在點選事件模型的捕獲階段對標籤內 javascript:...
的內容建立關鍵字黑名單,進行過濾審查,就可以做到我們想要的攔截效果。
對於 on* 類內聯事件也是同理,只是對於這類事件太多,我們沒辦法手動列舉,可以利用程式碼自動列舉,完成對內聯事件及內聯指令碼的攔截。
以攔截 a 標籤內的 href="javascript:...
為例,我們可以這樣寫:
// 建立關鍵詞黑名單
var keywordBlackList = [
'xss',
'BAIDU_SSP__wrapper',
'BAIDU_DSPUI_FLOWBAR'
];
document.addEventListener('click', function(e) {
var code = "";
// 掃描 <a href="javascript:"> 的指令碼
if (elem.tagName == 'A' && elem.protocol == 'javascript:') {
var code = elem.href.substr(11);
if (blackListMatch(keywordBlackList, code)) {
// 登出程式碼
elem.href = 'javascript:void(0)';
console.log('攔截可疑事件:' + code);
}
}
}, true);
/**
* [黑名單匹配]
* @param {[Array]} blackList [黑名單]
* @param {[String]} value [需要驗證的字串]
* @return {[Boolean]} [false -- 驗證不通過,true -- 驗證通過]
*/
function blackListMatch(blackList, value) {
var length = blackList.length,
i = 0;
for (; i < length; i++) {
// 建立黑名單正則
var reg = new RegExp(whiteList[i], 'i');
// 存在黑名單中,攔截
if (reg.test(value)) {
return true;
}
}
return false;
}
可以戳我檢視DEMO。(開啟頁面後開啟控制檯檢視 console.log)
點選圖中這幾個按鈕,可以看到如下:
這裡我們用到了黑名單匹配,下文還會細說。
靜態指令碼攔截
XSS 跨站指令碼的精髓不在於“跨站”,在於“指令碼”。
通常而言,攻擊者或者運營商會向頁面中注入一個<script>
指令碼,具體操作都在指令碼中實現,這種劫持方式只需要注入一次,有改動的話不需要每次都重新注入。
我們假定現在頁面上被注入了一個 <script src="http://attack.com/xss.js">
指令碼,我們的目標就是攔截這個指令碼的執行。
聽起來很困難啊,什麼意思呢。就是在指令碼執行前發現這個可疑指令碼,並且銷燬它使之不能執行內部程式碼。
所以我們需要用到一些高階 API ,能夠在頁面載入時對生成的節點進行檢測。
MutationObserver
MutationObserver 是 HTML5 新增的 API,功能很強大,給開發者們提供了一種能在某個範圍內的 DOM 樹發生變化時作出適當反應的能力。
說的很玄乎,大概的意思就是能夠監測到頁面 DOM 樹的變換,並作出反應。
MutationObserver() 該建構函式用來例項化一個新的Mutation觀察者物件。
MutationObserver(
function callback
);
相關文章
- http網路劫持與DNS劫持原理及預防HTTPDNS
- 前端防禦XSS前端
- 前端安全 - XSS前端
- 前端安全 — 淺談JavaScript攔截XSS攻擊前端JavaScript
- 前端針對 XSS 安全配置前端
- Web安全系列(四):XSS 的防禦Web
- 前端的安全問題與防禦策略前端
- web安全之XSS攻擊原理及防範Web
- 前端安全系列(一):如何防止XSS攻擊?前端
- 建議收藏!XSS與CSRF攻擊防範措施
- 如何有效防禦XSS攻擊?網路安全學習教程
- 不可忽視的前端安全問題——XSS攻擊前端
- 前端安全13條,除了XSS/CSRF你還知道哪些?前端
- 網站安全:dns汙染與dns劫持網站DNS
- Web安全-XSSWeb
- dns汙染與dns劫持,瞭解dns汙染與dns劫持,網站安全不可疏忽DNS網站
- dns劫持,dns劫持是什麼,該怎麼去預防dns劫持DNS
- JavaScript 前端效能優化之事件防抖JavaScript前端優化事件
- 淺談前端安全以及如何防範前端
- Web 安全之 XSSWeb
- 網路安全—xss
- JavaScript之節流與防抖JavaScript
- BGP劫持原理及如何防禦
- 網路安全與防範
- 詳解Xss 及SpringBoot 防範Xss攻擊(附全部程式碼)Spring Boot
- antixss防禦xss DLL庫檔案
- 前端攻擊 XSS 深入解析前端
- DNS劫持是怎麼回事?DNS劫持如何預防?(國科雲)DNS
- 資訊保安實踐Lab3-CSRF&XSS&點選劫持
- HTTP與HTTPS:為什麼HTTPS比HTTP更安全?HTTP
- 如何有效預防XSS?這幾招管用!!!
- 掌控安全作業 xss篇
- javascript之函式防抖與節流JavaScript函式
- 淺談JavaScript的防抖與節流JavaScript
- 【封神臺】前端滲透 XSS wp前端
- 前端戰五渣學JavaScript——防抖、節流和rAF前端JavaScript
- 好程式設計師web前端教程JavaScript系列之HTTP程式設計師Web前端JavaScriptHTTP
- 前端常見的安全問題及防範措施前端