[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请求进行服务端数据的更改。