HTML标签防XSS攻击过滤模块
发布于 2年前 作者 leizongmin 6108 次浏览

Build Status

过滤XSS攻击

安装

npm install xss

原理

通过标签白名单及属性白名单来过滤HTML标签,同时对包含特殊字符的属性值进行处理。默认配置可过滤大多数的XSS攻击代码,可根据实际应用场景来定制白名单及过滤方法。

使用方法

载入模块

var xss = require('xss');

使用默认的配置

var html = xss('<script>alert("xss");</script>');
console.log(html);

修改默认配置

// 添加或更新白名单中的标签 标签名(小写) = ['允许的属性列表(小写)']
xss.whiteList['p'] = ['class', 'style'];
// 删除默认的白名单标签
delete xss.whiteList['div'];

// 自定义处理属性值函数
xss.onTagAttr = function (tag, attr, vaule) {
  // tag:当前标签名(小写)
  // attr:当前属性名(小写)
  // value:当前属性值
  // 返回新的属性值,如果想使用默认的处理方式,不返回任何值即可
  // 比如把属性值中的双引号替换为&amp;quote;:return value.replace(/"/g, '&amp;quote;');
  // 以下为默认的处理代码:
  if (attr === 'href' || attr === 'src') {
    if (/\/\*|\*\//mg.test(value)) {
      return '#';
    }
    if (/^[\s"'`]*((j\s*a\s*v\s*a|v\s*b|l\s*i\s*v\s*e)\s*s\s*c\s*r\s*i\s*p\s*t\s*|m\s*o\s*c\s*h\s*a):/ig.test(value)) {
      return '#';
    }
  } else if (attr === 'style') {
    if (/\/\*|\*\//mg.test(value)) {
      return '#';
    }
    if (/((j\s*a\s*v\s*a|v\s*b|l\s*i\s*v\s*e)\s*s\s*c\s*r\s*i\s*p\s*t\s*|m\s*o\s*c\s*h\s*a):/ig.test(value)) {
      return '';
    }
  }
};

// 自定义处理不在白名单中的标签
xss.onIgnoreTag = function (tag, html) {
  // tag:当前标签名(小写),如:a
  // html:当前标签的HTML代码,如:<a href="ooxx">
  // 返回新的标签HTML代码,如果想使用默认的处理方式,不返回任何值即可
  // 比如将标签替换为[removed]:return '[removed]';
  // 以下为默认的处理代码:
  return html.replace(/</g, '&lt;').replace(/>/g, '&gt;');
}

使用临时配置

var options = {
  whiteList:   {},        // 若不指定则使用默认配置,可参考xss.whiteList
  onTagAttr:   function () {},  // 若不指定则使用默认配置,可参考xss.onTagAttr
  onIgnoreTag: function () {}   // 若不指定则使用默认配置,可参考xss.onIgnoreTag
};
var html = xss('<script>alert("xss");</script>', options);
console.log(html);

测试

单元测试

在源码目录执行命令:npm test

在线测试

在源码目录执行命令:node cli.js,可在命令行中输入HTML代码,并看到过滤后的代码

性能

解析速度为5.81MB/s,而另外一个validator模块的xss()函数速度仅为2.48MB/s

测试代码参考benchmark目录

项目地址:https://github.com/leizongmin/js-xss

希望此模块能完美解决XSS问题,我好将功补过 [[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[@suqian](/user/suqian)](/user/suqian)](/user/suqian)](/user/suqian)](/user/suqian)](/user/suqian)](/user/suqian)](/user/suqian)](/user/suqian)](/user/suqian)](/user/suqian)](/user/suqian)](/user/suqian)](/user/suqian)](/user/suqian)](/user/suqian)](/user/suqian)](/user/suqian)](/user/suqian)](/user/suqian)](/user/suqian)](/user/suqian)](/user/suqian)](/user/suqian)](/user/suqian)](/user/suqian)](/user/suqian)](/user/suqian)](/user/suqian)](/user/suqian)](/user/suqian)](/user/suqian)](/user/suqian)](/user/suqian)](/user/suqian)](/user/suqian)](/user/suqian)](/user/suqian)](/user/suqian)](/user/suqian)](/user/suqian)](/user/suqian)](/user/suqian)](/user/suqian)](/user/suqian)](/user/suqian)](/user/suqian)](/user/suqian)](/user/suqian)](/user/suqian)](/user/suqian)](/user/suqian)](/user/suqian)](/user/suqian)](/user/suqian)](/user/suqian) [[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[@snoopy](/user/snoopy)](/user/snoopy)](/user/snoopy)](/user/snoopy)](/user/snoopy)](/user/snoopy)](/user/snoopy)](/user/snoopy)](/user/snoopy)](/user/snoopy)](/user/snoopy)](/user/snoopy)](/user/snoopy)](/user/snoopy)](/user/snoopy)](/user/snoopy)](/user/snoopy)](/user/snoopy)](/user/snoopy)](/user/snoopy)](/user/snoopy)](/user/snoopy)](/user/snoopy)](/user/snoopy)](/user/snoopy)](/user/snoopy)](/user/snoopy)](/user/snoopy)](/user/snoopy)](/user/snoopy)](/user/snoopy)](/user/snoopy)](/user/snoopy)](/user/snoopy)](/user/snoopy)](/user/snoopy)](/user/snoopy)](/user/snoopy)](/user/snoopy)](/user/snoopy)](/user/snoopy)](/user/snoopy)](/user/snoopy)](/user/snoopy)](/user/snoopy)](/user/snoopy)](/user/snoopy)](/user/snoopy)](/user/snoopy)](/user/snoopy)](/user/snoopy)](/user/snoopy)](/user/snoopy)](/user/snoopy)](/user/snoopy)](/user/snoopy)](/user/snoopy)](/user/snoopy)](/user/snoopy)](/user/snoopy) [[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[@jiyinyiyong](/user/jiyinyiyong)](/user/jiyinyiyong)](/user/jiyinyiyong)](/user/jiyinyiyong)](/user/jiyinyiyong)](/user/jiyinyiyong)](/user/jiyinyiyong)](/user/jiyinyiyong)](/user/jiyinyiyong)](/user/jiyinyiyong)](/user/jiyinyiyong)](/user/jiyinyiyong)](/user/jiyinyiyong)](/user/jiyinyiyong)](/user/jiyinyiyong)](/user/jiyinyiyong)](/user/jiyinyiyong)](/user/jiyinyiyong)](/user/jiyinyiyong)](/user/jiyinyiyong)](/user/jiyinyiyong)](/user/jiyinyiyong)](/user/jiyinyiyong)](/user/jiyinyiyong)](/user/jiyinyiyong)](/user/jiyinyiyong)](/user/jiyinyiyong)](/user/jiyinyiyong)](/user/jiyinyiyong)](/user/jiyinyiyong)](/user/jiyinyiyong)](/user/jiyinyiyong)](/user/jiyinyiyong)](/user/jiyinyiyong)](/user/jiyinyiyong)](/user/jiyinyiyong)](/user/jiyinyiyong)](/user/jiyinyiyong)](/user/jiyinyiyong)](/user/jiyinyiyong)](/user/jiyinyiyong)](/user/jiyinyiyong)](/user/jiyinyiyong)](/user/jiyinyiyong)](/user/jiyinyiyong)](/user/jiyinyiyong)](/user/jiyinyiyong)](/user/jiyinyiyong)](/user/jiyinyiyong)](/user/jiyinyiyong)](/user/jiyinyiyong)](/user/jiyinyiyong)](/user/jiyinyiyong)](/user/jiyinyiyong)](/user/jiyinyiyong)](/user/jiyinyiyong)](/user/jiyinyiyong)](/user/jiyinyiyong)](/user/jiyinyiyong)](/user/jiyinyiyong) [[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[@j4cnodejs](/user/j4cnodejs)](/user/j4cnodejs)](/user/j4cnodejs)](/user/j4cnodejs)](/user/j4cnodejs)](/user/j4cnodejs)](/user/j4cnodejs)](/user/j4cnodejs)](/user/j4cnodejs)](/user/j4cnodejs)](/user/j4cnodejs)](/user/j4cnodejs)](/user/j4cnodejs)](/user/j4cnodejs)](/user/j4cnodejs)](/user/j4cnodejs)](/user/j4cnodejs)](/user/j4cnodejs)](/user/j4cnodejs)](/user/j4cnodejs)](/user/j4cnodejs)](/user/j4cnodejs)](/user/j4cnodejs)](/user/j4cnodejs)](/user/j4cnodejs)](/user/j4cnodejs)](/user/j4cnodejs)](/user/j4cnodejs)](/user/j4cnodejs)](/user/j4cnodejs)](/user/j4cnodejs)](/user/j4cnodejs)](/user/j4cnodejs)](/user/j4cnodejs)](/user/j4cnodejs)](/user/j4cnodejs)](/user/j4cnodejs)](/user/j4cnodejs)](/user/j4cnodejs)](/user/j4cnodejs)](/user/j4cnodejs)](/user/j4cnodejs)](/user/j4cnodejs)](/user/j4cnodejs)](/user/j4cnodejs)](/user/j4cnodejs)](/user/j4cnodejs)](/user/j4cnodejs)](/user/j4cnodejs)](/user/j4cnodejs)](/user/j4cnodejs)](/user/j4cnodejs)](/user/j4cnodejs)](/user/j4cnodejs)](/user/j4cnodejs)](/user/j4cnodejs)](/user/j4cnodejs)](/user/j4cnodejs)](/user/j4cnodejs)](/user/j4cnodejs) [[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[@atian25](/user/atian25)](/user/atian25)](/user/atian25)](/user/atian25)](/user/atian25)](/user/atian25)](/user/atian25)](/user/atian25)](/user/atian25)](/user/atian25)](/user/atian25)](/user/atian25)](/user/atian25)](/user/atian25)](/user/atian25)](/user/atian25)](/user/atian25)](/user/atian25)](/user/atian25)](/user/atian25)](/user/atian25)](/user/atian25)](/user/atian25)](/user/atian25)](/user/atian25)](/user/atian25)](/user/atian25)](/user/atian25)](/user/atian25)](/user/atian25)](/user/atian25)](/user/atian25)](/user/atian25)](/user/atian25)](/user/atian25)](/user/atian25)](/user/atian25)](/user/atian25)](/user/atian25)](/user/atian25)](/user/atian25)](/user/atian25)](/user/atian25)](/user/atian25)](/user/atian25)](/user/atian25)](/user/atian25)](/user/atian25)](/user/atian25)](/user/atian25)](/user/atian25)](/user/atian25)](/user/atian25)](/user/atian25)](/user/atian25)](/user/atian25)](/user/atian25)](/user/atian25)](/user/atian25)](/user/atian25) [[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[@saighost](/user/saighost)](/user/saighost)](/user/saighost)](/user/saighost)](/user/saighost)](/user/saighost)](/user/saighost)](/user/saighost)](/user/saighost)](/user/saighost)](/user/saighost)](/user/saighost)](/user/saighost)](/user/saighost)](/user/saighost)](/user/saighost)](/user/saighost)](/user/saighost)](/user/saighost)](/user/saighost)](/user/saighost)](/user/saighost)](/user/saighost)](/user/saighost)](/user/saighost)](/user/saighost)](/user/saighost)](/user/saighost)](/user/saighost)](/user/saighost)](/user/saighost)](/user/saighost)](/user/saighost)](/user/saighost)](/user/saighost)](/user/saighost)](/user/saighost)](/user/saighost)](/user/saighost)](/user/saighost)](/user/saighost)](/user/saighost)](/user/saighost)](/user/saighost)](/user/saighost)](/user/saighost)](/user/saighost)](/user/saighost)](/user/saighost)](/user/saighost)](/user/saighost)](/user/saighost)](/user/saighost)](/user/saighost)](/user/saighost)](/user/saighost)](/user/saighost)](/user/saighost)](/user/saighost)](/user/saighost)

34 回复

我只介意你趁我们聚会刷了那么多分。。。给减一半??? 对于超链接里的特殊字符都要转义成uri那种,像单引号和双引号你里面有吗?我只看到了tagName 不过这个,貌似论坛已经都处理了。

知错就改还是好孩子! 不管你这个xss如何, 总是一个好的开端. 我给你一个 XSS Cheat Sheet , 列出了各种XSS, 你测测这个模块能过滤掉多少! XSS Cheet Sheet

嘿嘿, 能处理 <a href="javas/**/cript:alert('XSS');"> 不?

@zxc122333 @j4cnodejs 暂时还没处理这个,我自己对xss也不熟悉啊,需要大家给出攻击方法来参考

@leizongmin 上面已给出 XSS Cheet Sheet 就是攻击方案

收藏了,另外问下,


这是什么用法?以前没有见过。。。

@zxc122333 我也没仔细研究过…

@zxc122333 去看了一下, 那个网站已经说得很清楚了,& JavaScript includes (works in Netscape 4.x), 只对Netscape 4.x 浏览器有效. 注意它每条XSS下的Browser support [IE7.0|IE6.0|NS8.1-IE] [NS8.1-G|FF2.0] [O9.02] **[NS4]**, 灰色的不支持,粗黑的支持

@suqian @j4cnodejs saighost @snoopy 现在已能过滤XSS Cheet Sheet中的大部分"异常代码“,并且解析速度还算可以,为6.26MB/s,而另外一个validator模块的xss()函数速度仅为2.82MB/s。

XSS测试代码:https://github.com/leizongmin/js-xss/blob/master/test/test_xss.js

请各位大大检阅。

我属于还是在膜拜楼主的. 学习了

@leizongmin 不错,我测过了, 除了你明示未实现的, 大部分XSS都能过滤出来, 表扬一记! 根据我们CMS实际使用情况, 这些tag也请列入默认白名单: em:['style'], cite:['style']

发现Bug了, xss()会把这样的代码: <a href='/user/test'><img src='/user_data/avatar/avatar.png' title='test1' /></a> 变成 <a href='/user_data/avatar/avatar.png'><img src='/user_data/avatar/avatar.png' title='test1' /></a>, 也就是说 a.href = img.src 了 你试试是不是这样?

刚试了一下,没有问题(更新一下github上的代码再试试):

<a href="/user/test"><img src="/user_data/avatar/avatar.png" title="test1"></a>

为了方便测试,写了个命令行工具:https://github.com/leizongmin/js-xss/blob/master/cli.js 你可以下载源码到本地,运行cli.js即可在窗口中输入HTML代码并看到过滤情况。

@leizongmin 发了一个pull request

又有更新,希望大家继续踊跃拍砖

老雷洗心革面可喜可贺啊~果断watch啊

这些都是跟你学的,神马XSS,神马白名单

0.0.2了,加油! 我昨天说的是,我想隐藏或移除标签(及标签里的内容), 怎么处理?

新增了一个用于处理这些标签的函数

xss.onIgnoreTag = function (tag, html) {
  // tag:当前标签名(小写),如:a
  // html:当前标签的HTML代码,如:<a href="ooxx">
  // 返回新的标签HTML代码,如果想使用默认的处理方式,不返回任何值即可
  // 比如将标签替换为[removed]:return '[removed]';
  // 以下为默认的处理代码:
  return html.replace(/</g, '&lt;').replace(/>/g, '&gt;');
}

比如要直接隐藏这些标签:

xss.onIgnoreTag = function (tag, html) {
  return '';
};

详细使用方法看这里:https://github.com/leizongmin/js-xss

为啥老雷在这一发回复我就提示有@ 我呢??

@leizongmin 这个我昨天试过了,挺好的!可它只能把标签隐藏掉,不能把标签的内容隐藏掉啊: <script>alert('xss');</script> => script是去掉了,可是 alert(‘xss’);显示出来了

@j4cnodejs 这个有点麻烦,假如输入的内容是这样的:

<script>alert('xss');
<div><p>该干嘛干嘛去</p>
<img src="ooxx">

<script>标签没有配对出现,那后面的其他标签都要隐藏么?

这次正常了,没提示@我

@leizongmin @了我7次了…老雷每次回复就@到我一次…

@saighost 难道是主题内容中有@到的用户, 底下每次回复都会有邮件?

@atian25 可是只有老雷的回复会@我

@leizongmin 这倒是个问题, 现在将就着用吧,反正只要不遇上黑恶代码, 不会对文章内容产生影响

支持,很实用的库。

回到顶部