[1]: alert(123);< /div>
[2]: http://www.baidu.com/#"onclick='alert(123)'
[3]: http://www.baidu.com/img.jpg#"onmouseover='alert(123)'
在社區這個應用場景下,引入
HTML標籤只是爲了進行一些排版的操做,而其餘的樣式定義等等都只會讓整個界面一團糟,更別說還有潛在的XSS漏洞風險。所以,其實咱們是不須要支持用戶輸入HTML標籤來進行內容排版的,一切均可以經過markdown來代替。而後經過簡單粗暴的HTML escape,就能夠消滅掉直接輸入HTML致使的XSS風險。
1. function escape(html) {
2. return html.replace(/&(?!\w+;)/g, '&')
3. .replace(/
</g, '
<')
4. .replace(
/>/g, '
>')
5. .replace(/"/g, '"');
6. }
然而這樣粗暴的進行
escape,會致使用戶輸入的代碼裏面的< > ;這些特殊字符也被轉義掉,不能正確顯示,須要先將代碼段提取出來保存,只轉義非代碼段的部分。因而這個escape函數變成了這樣:
1. function escape(html) {
2. var codeSpan = /(^|[^\\])(`+)([^\r]*?[^`])\2(?!`)/gm;
3. var codeBlock = /(?:\n\n|^)((?:(?:[ ]{4}|\t).*\n+)+)(\n*[ ]{0,3}[^ \t\n]|(?=~0))/g;
4. var spans = [];
5. var blocks = [];
6. var text = String(html).replace(/\r\n/g, '\n')
7. .replace('/\r/g', '\n');
8. text = '\n\n' + text + '\n\n';
9. texttext = text.replace(codeSpan, function(code) {
10.spans.push(code);
11.return '`span`';
12.});
13.text += '~0';
14.return text.replace(codeBlock, function (whole, code, nextChar) {
15.blocks.push(code);
16.return '\n\tblock' + nextChar;
17.})
18..replace(/&(?!\w+;)/g, '&')
19..replace(/
</g, '
<')
20..replace(
/>/g, '
>')
21..replace(/"/g, '"')
22..replace(/`span`/g, function() {
23.return spans.shift();
24.})
25..replace(/\n\tblock/g, function() {
26.return blocks.shift();
27.})
28..replace(/~0$/,'')
29..replace(/^\n\n/, '')
30..replace(/\n\n$/, '');
31.};
32.
而對於
markdown生成的<a>標籤和<img>標籤中的href屬性,必需要作URL有效性檢測或者作xss的過濾。這樣保證經過markdown生成的HTML代碼也是沒有XSS漏洞的。
由於
XSS的手段確實比較多,見XSS Filter Evasion Cheat Sheet。所以可以作粗暴的HTML escape是最安全的,可是並非每個地方均可以經過markdown來代替HTML代碼,因此不是每個地方都能用HTML escape,這個時候就須要其餘的手段來過濾XSS漏洞了。
XSS防範只能經過定義白名單的形式,例如只容許
<p> <div> <a>標籤,只容許href class style屬性。而後對每個可能形成XSS的屬性進行特定的過濾。
現有的
XSS過濾模塊,一個是node-validator, 一個是@雷宗民寫的js-xss。
不可以保證
XSS模塊能夠防範住任意的XSS***,可是起碼可以過濾掉大部分可以想象到的漏洞。node-validator的XSS()仍然有bug,對於<p on="></p>形式的代碼,會有雙引號不閉合的問題,致使HTML元素測漏。
模版引擎致使的XSS***
cnode社區採用的是
ejs做爲模版引擎,而在ejs中,提供了兩種輸出動態數據到頁面的方法:
<% =data %> //進行
xss過濾的輸出
<% -data %> //不過濾直接輸出
而全部的過濾必須有一個前提: 模版文件中的
HTML屬性的值等,必須使用雙引號。 例如:
1.
<img src='<%= reply.author.avatar_url %>' title='<%= reply.author.name %>'
/>
2.
<img src="<%= reply.author.avatar_url %>" title="<%= reply.author.name %>"
/>
上面兩條語句,第一句因爲使用的是單引號,用戶能夠經過構造一個
avatar_url中帶單引號,來截斷src屬性,後面就能夠隨意加javascript代碼了。
CSRF
***
CSRF***在
node的web開發框架connect和express等中都有了解決方方案。經過在訪客的session中存放一個隨機的_csrf字段,模版引擎在生成HTML文件的時候將這個_csrf值傳遞到前端,訪客提交的任意POST請求,都必須帶上這個字段進行驗證,保證了只有當前用戶在當前頁面上能夠進行修改的操做。
然而當頁面存在
XSS漏洞的時候,CSRF的這種防範措施就成了浮雲。惡意***者徹底能夠經過javascript代碼,獲取到其餘用戶的_csrf值,並直接模擬用戶的POST請求進行服務端數據的更改。