一、简介

sanitize-html提供了一个简单的HTML”消毒”工具来处理在Web中不安全的HTML内容,防止注入攻击。

它提供了简单清晰的API,也很适合清理由ckeditor和其他富文本编辑器创建的HTML片段。

sanitize-html是在htmlparser2模块上构建的;可以设置指定允许的标签以及每个标签允许的属性;还可以对hrefsrc属性进行验证,确保只包含httphttpsftpmailto URLs和相对URL;还支持对iframe标签的src属性做过滤(过滤主机名)。其中HTML注释不会被保留。

二、安装&使用

1、node

  • 安装
npm install sanitize-html
  • 使用
var sanitizeHtml = require('sanitize-html');
 
var dirty = 'some really tacky HTML';
var result = sanitizeHtml(dirty);

2、Browser

  • 安装

在github上克隆仓库,然后执行:

npm install
npm run minify

然后在dist目录中可以找到sanitize-html的压缩版和非压缩版。

也可以用node安装后,在node_modules\sanitize-html\dist目录中找到对应的文件。

  • 使用

在HTML中引入sanitize-html.js和自己的demo.js

<script type="text/javascript" src="sanitize-html.js"></script>
<script type="text/javascript" src="demo.js"></script>

demo.js

var html = "<strong>hello world</strong>";
console.log(sanitizeHtml(html));
console.log(sanitizeHtml("<img src='x' onerror=alert('img') />"));
console.log(sanitizeHtml("console.log('hello world')"));
console.log(sanitizeHtml("<script>alert('hello world')</script>"));

输出:

<strong>hello world</strong>

console.log('hello world')

其中输出的第二行和第四行为空行,内容已被忽略。

三、常用配置

部分属性默认配置如下:
{
	allowedTags: [ 'h3', 'h4', 'h5', 'h6', 'blockquote', 'p', 'a', 'ul', 'ol',
	  'nl', 'li', 'b', 'i', 'strong', 'em', 'strike', 'abbr', 'code', 'hr', 'br', 'div',
	  'table', 'thead', 'caption', 'tbody', 'tr', 'th', 'td', 'pre', 'iframe' ],
	disallowedTagsMode: 'discard',
	allowedAttributes: {
	  a: [ 'href', 'name', 'target' ],
	  // We don't currently allow img itself by default, but this
	  // would make sense if we did. You could add srcset here,
	  // and if you do the URL is checked for safety
	  img: [ 'src' ]
	},
	// Lots of these won't come up by default because we don't allow them
	selfClosing: [ 'img', 'br', 'hr', 'area', 'base', 'basefont', 'input', 'link', 'meta' ],
	// URL schemes we permit
	allowedSchemes: [ 'http', 'https', 'ftp', 'mailto' ],
	allowedSchemesByTag: {},
	allowedSchemesAppliedToAttributes: [ 'href', 'src', 'cite' ],
	allowProtocolRelative: true,
	enforceHtmlBoundary: false
}

1、自定义允许的标签

  • 样例

在默认配置的基础上允许img标签

var options = {
	allowedTags: sanitizeHtml.defaults.allowedTags.concat([ 'img' ])
};

var html = "<img src='x' onerror=alert('img') />";
console.log(sanitizeHtml(html, options));
  • 输出
<img src="x" />

2、自定义允许的属性

  • 样例

允许所有标签使用data-*title属性,允许p标签使用width属性:

var options = {
	allowedAttributes: {
	  	'p' : [ 'width'],
	  	'*' : ['data-*', 'title']
	}
};

console.log(sanitizeHtml("<div width='600px' data-id='123'>Good!</div>", options));
console.log(sanitizeHtml("<p title='Hi!' width='200px' height='100px'>Hello World!</p>", options));
  • 输出
<div data-id="123">Good!</div>
<p title="Hi!" width="200px">Hello World!</p>
在默认配置上增加允许的属性:
var options = {
	allowedAttributes: _.extend({}, sanitizeHtml.defaults.allowedAttributes, {'*': ["style"]})
}

3、允许某些属性的特定值

  • 样例

允许input标签以及type属性和class属性,但type属性只能是text、password、button其中之一,class属性只能从one、two、three中取值,允许多选:

var options = {
	allowedTags: sanitizeHtml.defaults.allowedTags.concat([ 'input' ]),
	allowedAttributes: {
	  	'input':[
	  		{
	  			'name': 'type',
	  			'values': ['text', 'password', 'button']
	  		},
	  		{
	  			'name': 'class',
	  			'multiple': true,
	  			'values': ['one', 'two', 'three']
	  		}
	  	]
	}
};

console.log(sanitizeHtml("<input type='password' class='one three'/>", options));
console.log(sanitizeHtml("<input type='text' class='xxx'/>", options));
console.log(sanitizeHtml("<input type='submit' class='two'/>", options));
  • 输出
<input type="password" class="one three" />
<input type="text" />
<input type class="two" />

4、允许所有标签和属性

  • 样例
var options = {
	allowedTags: false,
	allowedAttributes: false
};

console.log(sanitizeHtml("<h1 class='mystyle'>Hello World!</h1>", options));
console.log(sanitizeHtml("<img src='x' onerror=alert('img') />", options));
  • 输出
<h1 class="mystyle">Hello World!</h1>
<img src="x" onerror="alert('img')" />

5、不允许任何标签或属性

  • 样例
var options = {
	allowedTags: [],
	allowedAttributes: {}
};

console.log(sanitizeHtml("<a href='go'>Go to the future</a>"));
console.log(sanitizeHtml("<h1 class='mystyle'>Hello World!</h1>", options));
console.log(sanitizeHtml("<img src='x' onerror=alert('img') />", options));
  • 输出
<a href="go">Go to the future</a>
Hello World!

6、对不允许标签的处理

  • 配置

    对不允许标签的处理可以通过属性disallowedTagsMode控制,可选值如下:

    • discard

      默认值,将不允许的标签丢弃

    • escape

      将不允许的标签转义

    • recursiveEscape

      同escape,并将所有子标签应用相同的处理方式

  • 样例

console.log(sanitizeHtml("<h1 class='mystyle'>Hello World!</h1>"));
console.log(sanitizeHtml("<img src='x' onerror=alert('img') />"));

var options = {
	disallowedTagsMode: 'escape'
};

console.log(sanitizeHtml("<h1 class='mystyle'>Hello World!</h1>", options));
console.log(sanitizeHtml("<img src='x' onerror=alert('img') />", options));
  • 输出
Hello World!

&lt;h1&gt;Hello World!&lt;/h1&gt;
&lt;img src="x" /&gt;

7、标签或属性的转变(transformations)

sanitize-html支持将某种标签转换为另一种标签以及添加或修改属性:

  • 样例一

将所有的ol标签转为ul:

var options = {
	transformTags: {
	    'ol': 'ul',
	    'h3': 'p'
	}
};

var html = '<ol><li>item 1</li><li>item 2</li></ol>';
console.log(sanitizeHtml(html, options));
console.log(sanitizeHtml("<h3>Hello World!</h3>", options));

输出:

<ul><li>item 1</li><li>item 2</li></ul>
<p>Hello World!</p>
  • 样例二

可以使用simpleTransform方法简单的更改标签或添加属性(其中shouldMerge表示属性是否合并,默认为true):

simpleTransform(newTag, newAttributes, shouldMerge)

将ol标签转换为ul,并将class属性设置为bar:

var options = {
	allowedAttributes: {
		'*' : ['class']
	},
	transformTags:{
		'ol': sanitizeHtml.simpleTransform('ul', {class: 'bar'})
	}
};

var html = '<ol class="foo"><li>item 1</li><li>item 2</li></ol>';
console.log(sanitizeHtml(html, options));

输出:

<ul class="bar"><li>item 1</li><li>item 2</li></ul>
  • 样例三

使用自定义处理函数,实现效果同上:

var options = {
	allowedAttributes: {
		'*' : ['class']
	},
	transformTags:{
		'ol': function(tagName, attribs){
			//My own custom magic goes here
			
			return {
				tagName: 'ul',
				attribs: {
					class: 'bar'
				}
			};
		}
	}
};

var html = '<ol class="foo"><li>item 1</li><li>item 2</li></ol>';
console.log(sanitizeHtml(html, options));

输出:

<ul class="bar"><li>item 1</li><li>item 2</li></ul>
  • 样例四

添加或修改标签的文本内容:

var options = {
	allowedAttributes: {
		'a': ['href'],
		'*': ['class']
	},
	transformTags:{
		'a': function(tagName, attribs){
			return {
				tagName: tagName,
				text: 'Go to the future',
				attribs: attribs
			};
		},
		'p': function(tagName, attribs){
			return {
				tagName: tagName,
				text: 'Hello World!',
				attribs: {
					class: 'foo'
				}
			};
		}
	}
};

console.log(sanitizeHtml('<a href="http://feature.com"></a>', options));
console.log(sanitizeHtml('<p></p>', options));

输出:

<a href="http://feature.com">Go to the future</a>
<p class="foo">Hello World!</p>
参考资料

sanitize-html - npm