XSS 分為三種:反射型,存儲型和 DOM-based
如何攻擊
XSS 通過修改 HTML 節點或者執行 JS 代碼來攻擊網站。
例如通過 URL 獲取某些參數
<!-- http://www.domain.com?name=<script>alert(1)</script> --> <div>{{name}}</div>
上述 URL 輸入可能會將 HTML 改為 <div><script>alert(1)</script></div>
,這樣頁面中就憑空多了一段可執行腳本。這種攻擊類型是反射型攻擊,也可以說是 DOM-based 攻擊。
也有另一種場景,比如寫了一篇包含攻擊代碼 <script>alert(1)</script>
的文章,那么可能瀏覽文章的用戶都會被攻擊到。這種攻擊類型是存儲型攻擊,也可以說是 DOM-based 攻擊,並且這種攻擊打擊面更廣。
如何防御
最普遍的做法是轉義輸入輸出的內容,對於引號,尖括號,斜杠進行轉義
function escape(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, '`') str = str.replace(/\//g, '/') return str }
通過轉義可以將攻擊代碼 <script>alert(1)</script>
變成
// -> <script>alert(1)</script> escape('<script>alert(1)</script>')
對於顯示副文本來說,不能通過上面的辦法來轉義所有字符,因為這樣會把需要的格式也過濾掉。這種情況通常采用白名單過濾的辦法,當然也可以通過黑名單過濾,但是考慮到需要過濾的標簽和標簽屬性實在太多,更加推薦使用白名單的方式。
var xss = require('xss') var html = xss('<h1 id="title">XSS Demo</h1><script>alert("xss");</script>') // -> <h1>XSS Demo</h1><script>alert("xss");</script> console.log(html)
以上示例使用了 js-xss
來實現。可以看到在輸出中保留了 h1
標簽且過濾了 script
標簽