XSS攻擊一般指的是經過利用網頁開發時留下的漏洞,經過巧妙的方法注入惡意指令代碼到網頁,使用戶加載並執行攻擊者惡意製造的網頁程序。這些惡意網頁程序一般是JavaScript,但實際上也能夠包括Java、 VBScript、ActiveX、 Flash 或者甚至是普通的HTML。攻擊成功後,攻擊者可能獲得包括但不限於更高的權限(如執行一些操做)、私密網頁內容、會話和cookie等各類內容。(內容摘自百度百科)javascript
xss攻擊類型可分爲兩種,反射型和存儲型,顧名思義一種是保存進了數據庫,另外一種是在url中直接觸發,沒保存進數據庫,下面一一介紹。html
url參數直接注入前端
場景說明:在網站的搜索框內直接輸入攻擊腳本java
// 搜索框搜索
http://localhost/?keyWord=<script>alert(111)</script>
複製代碼
存儲到DB後讀取時注入git
場景說明:攻擊腳本做爲留言內容,提交給後臺保存,刷新頁面後端返回攻擊腳本給前端github
// 留言板插入數據庫
留言測試<script>alert(222)</script>//留言內容 複製代碼
攻擊腳本經過接口存入數據庫中,當頁面刷新時,插入的腳本替換頁面HTML節點內容,腳本隨即執行,引起漏洞攻擊正則表達式
<!-- content變量被攻擊腳本替換 -->
<div>
{{content}}
</div>
<div>
<script>
</script>
</div>
複製代碼
經過修改或者添加HTML屬性,觸發攻擊事件數據庫
<!-- 圖片地址異常後,引起錯誤事件 -->
<img src="#{image}"/>
<img src=" 1"onerror="alert(1)" />
複製代碼
經過獲取用戶輸入的變量或者其餘保存的變量,在腳本中打印後端
<script>
var data = params;
console.log(data)
// 輸入內容
params = "hello":alert(1)
</script>
複製代碼
富文本須要保留HTML
HTML有XSS攻擊風險瀏覽器
總體思路:轉義
轉義時機:
轉義方式更傾向於第一種:由於輸入是一次性性能消費,而輸出會是屢次,形成性能浪費,本文的示例代碼內容因爲我的編譯、演示方便緣由是採用第二種方式-返回時轉義,請各位讀者知曉
處理思路:轉義< >
,使之不能以html
標籤的形式保存或者返回給前端
//轉義函數
var escapeHtml = function(str){
str = str.replace(/</g,'<');
str = str.replace(/>/g,'>')
return str
}
複製代碼
// 轉義前
<script>alert(111)</script>
// 轉移後
<script>alert(111)</script>
// 頁面dom呈現
<script>alert(111)</script>//字符串類型
||
<span><script>alert(111)</script></span>
複製代碼
處理思路:轉義"
引號,使標籤內屬性不能自閉合,引發觸發事件
// 轉義函數
var escapeHtmlProperty = function(str){
if(!str)return '';
str = str.replace(/"/g,'&quto;');//替換雙引號
str = str.replace(/'/g,''');//替換單引號
str = str.replace(/ /g,' ');//替換空格
return str;
}
複製代碼
// 轉義前
<img src=" 1"onerror="alert(1)" />
// 轉義後
<img src="1&quto; onerror=&quto;alert(1)" />
// 頁面dom呈現
<img src="1&quto; onerror=&quto;alert(1)" />
複製代碼
那麼問題來了,轉義了HTML
屬性中的大於號、小於號,會對元素產生其餘影響嗎?轉義了HTML
節點內容中的單引號、雙引號、空格,會對元素產生其餘影響嗎?
答案是不會產生影響的,讀者能夠自行驗證。
此時能夠合併上面的兩個函數,總體處理HTML
節點和屬性,合併函數以下:
// 轉義函數
var escapeHtml = function(str){
str = str.replace(/&/g,'&');//&符號也須要轉義,可是必定放在第一個轉
str = str.replace(/</g,'<');
str = str.replace(/>/g,'>')
str = str.replace(/"/g,'&quto;');//替換雙引號
str = str.replace(/'/g,''');//替換單引號
// 空格的轉義影響其實並不大,能夠省略
// str = str.replace(/ /g,' ');//替換空格
return str
}
複製代碼
處理思路:轉義雙引號或者JSON_encode
//轉義函數
var escapeForJs =function(str){
if(!str)return '';
str = str.replace(/"/g,'\\"');//js中雙引號的轉義和HTML中不一樣,不能使用HTML轉義方法
return str;
}
複製代碼
原函數:
<script>
var str = "!{keyWord}";
console.log(str)
</script>
//hello world";alert(1);"
//轉義前
<script> hello world alert(1)已經被彈出 </script>
//轉義後
hello world";alert(1);"
複製代碼
然而這樣就安全了嗎?
答案確定不是!
單引號、script標籤、雙引號、空格...均可以引起攻擊,更爲安全的方式-JSON_encode轉義
JSON_encode轉義-JSON.stringify
演示代碼:
// 轉義函數
JSON.stringify(參數)
複製代碼
//轉義前
hello world";alert(1);"
//轉義後
hello world";alert(1);"
複製代碼
處理思路:過濾
好比
script
標籤、onerror
標籤...所有過濾掉
按照白名單過濾保留部分標籤和屬性,只容許保留名單內的標籤、屬性
示例攻擊代碼:
<!-- 可能輸入的攻擊腳本 -->
<font color=\"red\">這是紅色字</font><script>alert('富文本')</script>
<a href=\"javascript:alert(1)\"></a>
<img src=\"abc\" onerror=\"alert(1)\">
..onfocus,
..onmounseover,
..onmenucontext,
...
複製代碼
//過濾函數
var xssFilter = function (html) {
if (!html) return '';
html = html.replace(/<\s*\/?script\s*>/g,'');
html = html.replace(/javascript:[^'"]*/g,'');
html = html.replace(/onerror\s*=\s*['"]?[^'"]*['"]?/g,'');
...
return html
}
複製代碼
HTML中帶有事件觸發的都有可能成爲攻擊的突破口,面對這種狀況,怎麼防護呢?下面介紹白名單過濾。
處理思路:整理富文本中全部的標籤屬性,過濾只容許這些屬性經過,其餘屬性則不容許經過
處理方式:將HTML解析成樹狀結構,和瀏覽器解析HTML過程相似,再去遍歷樹狀結構元素,在過濾範圍內的容許經過,沒在過濾範圍內的,則去掉
示例攻擊代碼:
//可能輸入的攻擊腳本
<font color=\"red\">這是紅色字</font><script>alert('富文本')</script>
<a href=\"javascript:alert(1)\"></a>
<img src=\"abc\" onerror=\"alert(1)\">
..onfocus,
..onmounseover,
..onmenucontext,
...
複製代碼
//過濾代碼
var xssFilter = function (html) {
if (!html) return '';
//白名單
var whiteList = {
'img': ['src'],
'font':['color','size'],
'a':['href']
};
var cheerio = require('cheerio');
var $ = cheerio.load(html);
$('*').each(function (index, elem) {
if (!whiteList[elem.name]) {
$(elem).remove();
return;
}
for (var attr in elem.attribs) {
if (whiteList[elem.name].indexOf(attr) === -1) {
$(elem).attr(attr, null);
}
}
})
return $.html()
}
複製代碼
cheerio是爲服務器特別定製的,快速、靈活、實施的以jQuery爲核心實現的對DOM操做方案
//基礎用法
const cheerio = require('cheerio');
const $ = cheerio.load('<h2 class="title">Hello world</h2>');
$('h2.title').text('Hello there!');
$('h2').addClass('welcome');
$.html();
//=> <html><head></head><body><h2 class="title welcome">Hello there!</h2></body></html>
複製代碼
安裝方式、語法等此處不過多介紹,須要的讀者請跳轉官網閱讀
代碼中主要使用它把HTML
結構轉換成可直接使用的數據結構,再循環去比較、移除。
那有沒有現有的可直接使用的第三方框架嗎?答案是確定的
xss
是一個用於對用戶輸入的內容進行過濾,以免遭受 XSS 攻擊的模塊。主要用於論壇、博客、網上商店等等一些可容許用戶錄入頁面排版、格式控制相關的 HTML 的場景,xss模塊經過白名單來控制容許的標籤及相關的標籤屬性,另外還提供了一系列的接口以便用戶擴展,比其餘同類模塊更爲靈活中文官網地址
示例代碼:
//過濾函數
var xssFilter = function (html) {
if (!html) return '';
var xss = require('xss');
var ret = xss(html);
return ret;
}
複製代碼
就是如此的簡單,固然還須要調整,此處就不過多介紹了,下面介紹下xss
模塊的特性及基本使用方法。
在Node.js
中使用
var xss = require("xss");
var html = xss('<script>alert("xss");</script>');
console.log(html);
複製代碼
在瀏覽器端使用
<script src="https://rawgit.com/leizongmin/js-xss/master/dist/xss.js"></script>
<script> // 使用函數名 filterXSS,用法同樣 var html = filterXSS('<script>alert("xss");</scr' + 'ipt>'); alert(html); </script> 複製代碼
其餘使用模式及用法請參考官網案例
若是須要簡單、快速、安全的開發選用第三方的庫固然更好,可是使用過程可能會有這樣或者那樣的問題,達不到業務的要求等等,相較於第三方的庫本身設置白名單去處理的話,就更容易控制、定製化效果明顯,相對問題可能會更少,仁者見仁智者見智,讀者根據實際狀況可自行選擇。
內容安全策略 (CSP) 是一個額外的安全層,用於檢測並削弱某些特定類型的攻擊,包括跨站腳本 (XSS) 和數據注入攻擊等。不管是數據盜取、網站內容污染仍是散發惡意軟件,這些攻擊都是主要的手段。
配置內容安全策略涉及到添加 Content-Security-Policy HTTP頭部到一個頁面,並配置相應的值,以控制用戶代理(瀏覽器等)能夠爲該頁面獲取哪些資源。
一個網站管理者想要全部內容均來自站點的同一個源 (不包括其子域名)
Content-Security-Policy: default-src 'self'
複製代碼
一個在線郵箱的管理者想要容許在郵件裏包含HTML,一樣圖片容許從任何地方加載,但不容許JavaScript或者其餘潛在的危險內容(從任意位置加載)。
Content-Security-Policy: default-src 'self' *.mailsite.com; img-src *
複製代碼
更多示例及用法請參考MDN-CSP
安全做爲系統的壁壘,重要程度不用多說。 XSS攻擊更是安全防護的重中之中。 本文記錄的是筆者在開發過程當中遇到的問題及處理的思路。可供有相似問題的讀者參考。 其餘安全方面的文章筆者會持續更新,歡迎各位讀者提出意見和建議。