摘要:跨站腳本攻擊,縮寫為。這就是攻擊最簡單的一個案例。漏洞產生的原因是攻擊者注入的數據反映在響應中。而且富文本攻擊的防御相對比較麻煩。默認配置下不允許執行內聯代碼塊內容,內聯事件,內聯樣式,以及禁止執行和。
跨站腳本攻擊(Cross Site Scripting),縮寫為XSS。惡意攻擊者往Web頁面里插入惡意javaScript代碼,當用戶瀏覽該頁之時,嵌入其中Web里面的javaScript代碼會被執行,從而達到惡意攻擊用戶的目的。
一個簡單的XSS攻擊
代碼:
async function(ctx, next){ ctx.set("X-XSS-Protection",0); ctx.render("index",{from:ctx.query.from}); };
注意:插入X-XSS-Protection頭部使瀏覽器XSS攔截器失效。
開始攻擊:
大家發現網頁執行了一段腳本,而且這段腳本是用戶惡意輸入的。這就是XSS攻擊最簡單的一個案例。把原本應該顯示純文本的地方,執行了一段黑客寫入的腳本。
那XSS攻擊有什么危害呢?
1、盜取各類用戶帳號
2、控制企業數據,包括讀取、篡改、添加、刪除企業敏感數據的能力
3、盜竊企業重要的具有商業價值的資料
4、非法轉賬
5、強制發送電子郵件
6、網站掛馬
7、控制受害者機器向其它網站發起攻擊
XSS攻擊的分類
1、反射型
又稱為非持久性跨站點腳本攻擊。漏洞產生的原因是攻擊者注入的數據反映在響應中。非持久型XSS攻擊要求用戶訪問一個被攻擊者篡改后的鏈接,用戶訪問該鏈接時,被植入的攻擊腳本被用戶游覽器執行,從而達到攻擊目的。也就是我上面舉的那個簡單的XSS攻擊案例,通過url參數直接注入。然后在響應的數據中包含著危險的代碼。
當黑客把這個鏈接發給你,你就中招啦!
2、存儲型
又稱為持久型跨站點腳本,它一般發生在XSS攻擊向量(一般指XSS攻擊代碼)存儲在網站數據庫,當一個頁面被用戶打開的時候執行。持久的XSS相比非持久性XSS攻擊危害性更大,容易造成蠕蟲,因為每當用戶打開頁面,查看內容時腳本將自動執行。
該網頁有一個發表評論的功能,該評論會寫入后臺數據庫,并且訪問主頁的時候,會從數據庫中加載出所有的評論。
當我添加一個評論,并且暗藏一個腳本,如下圖:
當別人訪問主頁的時候,剛剛黑客寫入的評論里面的腳本被瀏覽器當成代碼執行了,用戶莫名其妙受到攻擊:
上面就是兩種XSS攻擊的兩種基本類型。當然黑客不會彈出一個框框給你,告訴你被攻擊,黑客不會這么傻的~他可以在用戶不知情的情況下,盜取用戶的cookie,改變網頁業務邏輯等等。
XSS攻擊的注入點
1、HTML節點內容
這個其實就是我之前演示的,HTML節點中暗藏攻擊腳本。
2、HTML屬性
這里img的src屬性是由用戶傳遞過來的值,當用戶把圖片地址寫成:1"%20onerror="alert(%27哈哈被攻擊%27)
大家看下面發生了什么:
3、JavaScript代碼 (字符串提前關閉)
當JavaScript代碼中有一個變量是由用戶提供的數據,這個數據也有可能之前被寫入了數據庫。如下圖,當用戶輸入的內容為:
小柚子";alert(%27哈哈你被攻擊了!%27);"
4、富文本
大家都知道,富文本其實就是一段HTML。既然它是一段HTML,那么就存在XSS攻擊。而且富文本攻擊的防御相對比較麻煩。
XSS攻擊防御
chrome瀏覽器自帶防御,可攔截反射性XSS(HTML內容和屬性),js和富文本的無法攔截,所以我們必須得自己做一些防御手段。
1、HTML節點內容的防御
將用戶輸入的內容進行轉義:
var escapeHtml = function(str) { str = str.replace(/"); return str; }
ctx.render("index", {comments, from: escapeHtml(ctx.query.from || "")});
2、HTML屬性的防御
對空格,單引號,雙引號進行轉義
var escapeHtmlProperty = function (str) { if(!str) return ""; str = str.replace(/"/g,"&quto;"); str = str.replace(/"/g,"'"); str = str.replace(/ /g," "); return str; }
ctx.render("index", {posts, comments, from:ctx.query.from || "", avatarId:escapeHtmlProperty(ctx.query.avatarId || "")});
3、JavaScript的防御
對引號進行轉義
var escapeForJS = function(str){ if(!str) return ""; str = str.replace(//g,""); str = str.replace(/"/g,"""); return str; }
4、富文本的防御
富文本的情況非常的復雜,js可以藏在標簽里,超鏈接url里,何種屬性里。
所以我們不能過用上面的方法做簡單的轉義。因為情況實在太多了。
現在我們換個思路,
提供兩種過濾的辦法:
1)黑名單
我們可以把 onerror 這種危險標簽或者屬性納入黑名單,過濾掉它。但是我們想,這種方式你要考慮很多情況,你也有可能漏掉一些情況等。
2)白名單
這種方式只允許部分標簽和屬性。不在這個白名單中的,一律過濾掉它。但是這種方式編碼有點麻煩,我們需要去解析html樹狀結構,然后進行過濾,把過濾后安全的html在輸出。
這里提供一個包,幫助我們去解析html樹狀結構,它使用起來和jquery非常的類似。
npm install cheerio --save
var xssFilter = function(html) { if(!html) return ""; var cheerio = require("cheerio"); var $ = cheerio.load(html); //白名單 var whiteList = { "html" : [""], "body" : [""], "head" : [""], "div" : ["class"], "img" : ["src"], "a" : ["href"], "font":["size","color"] }; $("*").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(); } console.log(xssFilter("你好大家可以看到: