sanitize-html
sanitize-html提供了一个简单的HTML清理工具,具有清晰的API。
sanitize-html具有容错性。它非常适合清理由CKEditor和其他富文本编辑器创建的HTML片段。特别是在从Word复制粘贴时,它可以方便地移除不需要的CSS。
sanitize-html允许你指定想要允许的标签,以及每个标签允许的属性。如果一个属性是已知的非布尔值,且为空,它将被移除。例如,checked
可以为空,但href
不能。
如果一个标签不被允许,标签的内容不会被丢弃。这里有一些例外情况,将在下面的"丢弃不允许标签的全部内容"部分讨论。
poorly闭合的p
和img
元素的语法会被清理。
href
属性会被验证,以确保它们只包含http
、https
、ftp
和mailto
URL。相对URL也是允许的。src
属性也是如此。
通过过滤主机名来允许特定URL作为iframe标签的src
也是支持的。
HTML注释不会被保留。
此外,sanitize-html
会转义所有文本内容 - 这意味着和号、大于号和小于号会被转换为它们对应的HTML字符引用(&
--> &
,<
--> <
,等等)。另外,在属性值中,引号也会被转义("
--> "
)。
要求
sanitize-html旨在与Node.js一起使用,支持Node 10+。它的所有npm依赖都是纯JavaScript。sanitize-html基于优秀的htmlparser2
模块构建。
关于TypeScript
sanitize-html不是用TypeScript编写的,也没有计划直接支持它。不过,有一个社区支持的类型定义,@types/sanitize-html
。
npm install -D @types/sanitize-html
如果你的tsconfig.json
文件中没有设置esModuleInterop=true
,你需要这样导入它:
import * as sanitizeHtml from 'sanitize-html';
使用TypeScript时,由于依赖于htmlparser2
的类型,最低支持的版本为>=4.5。
使用@types/sanitize-html
时遇到的任何问题或疑问,应按照该项目的贡献指南向其维护者反馈。
如何使用
浏览器
首先考虑:为什么要在浏览器中使用它? 记住,服务器绝不能信任浏览器。 你不能在服务器以外的地方为保存在服务器上的HTML进行清理。
但是,也许你想在浏览器中立即预览清理后的HTML。或者让浏览器在每次页面加载时进行清理工作。如果你想这样做,也是可以的!
- 安装包:
npm install sanitize-html
或
yarn add sanitize-html
sanitize-html 2.x版本的主要变化是不再包含一个可直接用于浏览器的构建版本。开发者需要像处理其他依赖一样,将sanitize-html包含在他们的项目构建中(例如,webpack)。因此,虽然sanitize-html不再可以直接在HTML中链接使用,但开发者现在可以更容易地根据需求处理它。
一旦构建完成并在浏览器中与其他项目JavaScript链接,就可以在前端代码中使用它来清理HTML字符串:
import sanitizeHtml from 'sanitize-html';
const 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>"));
Node(推荐)
从控制台安装模块:
npm install sanitize-html
导入模块:
// 在ES模块中
import sanitizeHtml from 'sanitize-html';
// 或者在CommonJS中
const sanitizeHtml = require('sanitize-html');
在你的JavaScript应用中使用它:
const dirty = '一些非常难看的HTML';
const clean = sanitizeHtml(dirty);
这将允许我们默认允许的标签和属性列表通过。这是一个不错的设置,但可能不完全是你想要的。所以:
// 只允许一个超级受限的标签和属性集
const clean = sanitizeHtml(dirty, {
allowedTags: [ 'b', 'i', 'em', 'strong', 'a' ],
allowedAttributes: {
'a': [ 'href' ]
},
allowedIframeHostnames: ['www.youtube.com']
});
搞定!
默认选项
allowedTags: [
"address", "article", "aside", "footer", "header", "h1", "h2", "h3", "h4",
"h5", "h6", "hgroup", "main", "nav", "section", "blockquote", "dd", "div",
"dl", "dt", "figcaption", "figure", "hr", "li", "main", "ol", "p", "pre",
"ul", "a", "abbr", "b", "bdi", "bdo", "br", "cite", "code", "data", "dfn",
"em", "i", "kbd", "mark", "q", "rb", "rp", "rt", "rtc", "ruby", "s", "samp",
"small", "span", "strong", "sub", "sup", "time", "u", "var", "wbr", "caption",
"col", "colgroup", "table", "tbody", "td", "tfoot", "th", "thead", "tr"
],
nonBooleanAttributes: [
'abbr', 'accept', 'accept-charset', 'accesskey', 'action',
'allow', 'alt', 'as', 'autocapitalize', 'autocomplete',
'blocking', 'charset', 'cite', 'class', 'color', 'cols',
'colspan', 'content', 'contenteditable', 'coords', 'crossorigin',
'data', 'datetime', 'decoding', 'dir', 'dirname', 'download',
'draggable', 'enctype', 'enterkeyhint', 'fetchpriority', 'for',
'form', 'formaction', 'formenctype', 'formmethod', 'formtarget',
'headers', 'height', 'hidden', 'high', 'href', 'hreflang',
'http-equiv', 'id', 'imagesizes', 'imagesrcset', 'inputmode',
'integrity', 'is', 'itemid', 'itemprop', 'itemref', 'itemtype',
'kind', 'label', 'lang', 'list', 'loading', 'low', 'max',
'maxlength', 'media', 'method', 'min', 'minlength', 'name',
'nonce', 'optimum', 'pattern', 'ping', 'placeholder', 'popover',
'popovertarget', 'popovertargetaction', 'poster', 'preload',
'referrerpolicy', 'rel', 'rows', 'rowspan', 'sandbox', 'scope',
'shape', 'size', 'sizes', 'slot', 'span', 'spellcheck', 'src',
'srcdoc', 'srclang', 'srcset', 'start', 'step', 'style',
'tabindex', 'target', 'title', 'translate', 'type', 'usemap',
'value', 'width', 'wrap',
// 事件处理程序
'onauxclick', 'onafterprint', 'onbeforematch', 'onbeforeprint',
'onbeforeunload', 'onbeforetoggle', 'onblur', 'oncancel',
'oncanplay', 'oncanplaythrough', 'onchange', 'onclick', 'onclose',
'oncontextlost', 'oncontextmenu', 'oncontextrestored', 'oncopy',
'oncuechange', 'oncut', 'ondblclick', 'ondrag', 'ondragend',
'ondragenter', 'ondragleave', 'ondragover', 'ondragstart',
'ondrop', 'ondurationchange', 'onemptied', 'onended',
'onerror', 'onfocus', 'onformdata', 'onhashchange', 'oninput',
'oninvalid', 'onkeydown', 'onkeypress', 'onkeyup',
'onlanguagechange', 'onload', 'onloadeddata', 'onloadedmetadata',
'onloadstart', 'onmessage', 'onmessageerror', 'onmousedown',
'onmouseenter', 'onmouseleave', 'onmousemove', 'onmouseout',
'onmouseover', 'onmouseup', 'onoffline', 'ononline', 'onpagehide',
'onpageshow', 'onpaste', 'onpause', 'onplay', 'onplaying',
'onpopstate', 'onprogress', 'onratechange', 'onreset', 'onresize',
'onrejectionhandled', 'onscroll', 'onscrollend',
'onsecuritypolicyviolation', 'onseeked', 'onseeking', 'onselect',
'onslotchange', 'onstalled', 'onstorage', 'onsubmit', 'onsuspend',
'ontimeupdate', 'ontoggle', 'onunhandledrejection', 'onunload',
'onvolumechange', 'onwaiting', 'onwheel'
],
disallowedTagsMode: 'discard',
allowedAttributes: {
a: [ 'href', 'name', 'target' ],
// 我们目前默认不允许img标签本身,但如果允许的话,
// 这些属性是有意义的。
img: [ 'src', 'srcset', 'alt', 'title', 'width', 'height', 'loading' ]
},
// 很多这些标签默认情况下不会出现,因为我们不允许它们
selfClosing: [ 'img', 'br', 'hr', 'area', 'base', 'basefont', 'input', 'link', 'meta' ],
// 我们允许的URL schemes
allowedSchemes: [ 'http', 'https', 'ftp', 'mailto', 'tel' ],
allowedSchemesByTag: {},
allowedSchemesAppliedToAttributes: [ 'href', 'src', 'cite' ],
allowProtocolRelative: true,
enforceHtmlBoundary: false,
parseStyleAttributes: true
常见用例
"我喜欢你的设置,但我想再添加一个标签。有什么方便的方法吗?"
当然:
const clean = sanitizeHtml(dirty, {
allowedTags: sanitizeHtml.defaults.allowedTags.concat([ 'img' ])
});
如果你没有指定allowedTags
或allowedAttributes
,我们的默认列表将被应用。所以如果你真的想要一个空列表,请明确指定。
"如果我想允许所有标签或所有属性怎么办?"
很简单!不要在选项中省略allowedTags
或allowedAttributes
,而是将其中一个或两个都设置为false
:
allowedTags: false,
allowedAttributes: false
"如果我想允许空属性,即使是像href这样通常没有意义的情况?"
非常简单!将nonBooleanAttributes
设置为[]
。
nonBooleanAttributes: []
"如果我想删除所有空属性,包括有效的属性?"
同样非常简单!将nonBooleanAttributes
设置为['*']
。
注意:这将破坏常见的有效情况,如checked
和selected
,所以这可能不是你想要的。对于大多数普通的HTML使用,最好避免进行这种更改。
nonBooleanAttributes: ['*']
"如果我不想允许任何标签怎么办?"
也很简单!将allowedTags
设置为[]
,将allowedAttributes
设置为{}
。
allowedTags: [],
allowedAttributes: {}
"如果我想让不允许的标签被转义而不是丢弃怎么办?"
如果你将disallowedTagsMode
设置为discard
(默认值),不允许的标签将被丢弃。任何文本内容或子标签仍然会被包含,取决于各个子标签是否被允许。
如果你将disallowedTagsMode
设置为completelyDiscard
,不允许的标签及其包含的任何内容都将被丢弃。任何子标签仍然会被包含,只要这些个别子标签是被允许的。
如果你将disallowedTagsMode
设置为escape
,不允许的标签将被转义而不是丢弃。任何文本或子标签都会正常处理。
如果你将disallowedTagsMode
设置为recursiveEscape
,不允许的标签将被转义而不是丢弃,并且所有子标签都会受到相同的处理,无论它们是否被允许。
"如果我只想允许某些属性上的特定值怎么办?"
在allowedAttributes
中配置属性时,只需使用一个带有属性name
和允许的values
数组的对象。在下面的例子中,sandbox="allow-forms allow-modals allow-orientation-lock allow-pointer-lock allow-popups allow-popups-to-escape-sandbox allow-scripts"
将变成sandbox="allow-popups allow-scripts"
:
allowedAttributes: {
iframe: [
{
name: 'sandbox',
multiple: true,
values: ['allow-popups', 'allow-same-origin', 'allow-scripts']
}
]
}
使用multiple: true
,同一属性中可以出现多个允许的值,用空格分隔。否则,属性必须精确匹配一个且仅一个允许的值。
"如果我想保持SVG元素和属性的原始大小写怎么办?"
如果你在内容中包含了像linearGradient
这样的SVG元素,并注意到它们由于大小写敏感性问题而无法按预期渲染,那么防止sanitize-html
将元素和属性名称转换为小写是至关重要的。当SVG因其大小写敏感的标签(如linearGradient
)和属性(如viewBox
)被无意中转换为小写而无法正确显示时,通常会出现这种情况。
为了解决这个问题,请确保在sanitize-html配置的解析器选项中设置lowerCaseTags: false
和lowerCaseAttributeNames: false
。这个调整可以阻止库改变标签和属性的大小写,从而保持SVG内容的完整性。
allowedTags: [ 'svg', 'g', 'defs', 'linearGradient', 'stop', 'circle' ],
allowedAttributes: false,
parser: {
lowerCaseTags: false,
lowerCaseAttributeNames: false
}
属性通配符
你可以使用 *
通配符来允许具有某个前缀的所有属性:
allowedAttributes: {
a: [ 'href', 'data-*' ]
}
你也可以使用 *
作为标签名,以允许列出的属性对任何标签都有效:
allowedAttributes: {
'*': [ 'href', 'align', 'alt', 'center', 'bgcolor' ]
}
其他选项
允许的CSS类
如果你希望在特定元素上允许特定的CSS类,可以使用 allowedClasses
选项。其他CSS类将被丢弃。
这意味着该元素上允许使用 class
属性。
// 只允许在p标签上使用一组受限的CSS类
const clean = sanitizeHtml(dirty, {
allowedTags: [ 'p', 'em', 'strong' ],
allowedClasses: {
'p': [ 'fancy', 'simple' ]
}
});
类似于 allowedAttributes
,你可以使用 *
来允许具有某个前缀的类,或使用 *
作为标签名以允许列出的类对任何标签都有效:
allowedClasses: {
'code': [ 'language-*', 'lang-*' ],
'*': [ 'fancy', 'simple' ]
}
此外,还支持正则表达式:
allowedClasses: {
p: [ /^regex\d{2}$/ ]
}
如果某个标签的 allowedClasses
设置为 false
,则该标签的所有类都将被允许。
注意:建议你的正则表达式总是以
^
开头,这样你就要求一个已知的前缀。没有^
也没有$
的正则表达式只要求某些内容出现在中间。
允许的CSS样式
如果你希望在特定元素上允许特定的CSS样式,可以使用 allowedStyles
选项。只需在给定属性的数组中声明所需属性作为正则表达式选项。特定元素将从全局(*
)属性继承允许列表中的属性。其他CSS类将被丢弃。
你还必须使用 allowedAttributes
来激活相关元素的 style
属性。否则这个功能将永远不会起作用。
构造正则表达式时,不要忘记 ^
和 $
。 仅仅说"字符串应该包含这个"是不够的。它还必须说"而且只有这个"。
内联样式中的URL不会通过任何机制进行过滤,除了你的正则表达式。
const clean = sanitizeHtml(dirty, {
allowedTags: ['p'],
allowedAttributes: {
'p': ["style"],
},
allowedStyles: {
'*': {
// 匹配HEX和RGB
'color': [/^#(0x)?[0-9a-f]+$/i, /^rgb\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*\)$/],
'text-align': [/^left$/, /^right$/, /^center$/],
// 匹配带px、em或%的任何数字
'font-size': [/^\d+(?:px|em|%)$/]
},
'p': {
'font-size': [/^\d+rem$/]
}
}
});
丢弃 <html></html>
标签外的文本
一些文本编辑应用程序生成HTML以允许复制到Web应用程序。这些有时可能在终止 html
标签后包含不需要的控制字符。默认情况下,sanitize-html不会丢弃这些字符,而是将它们包含在净化后的字符串中。可以使用 enforceHtmlBoundary
选项修改此行为。
将此选项设置为true将指示sanitize-html丢弃 html
标签边界之外的所有字符 -- <html>
之前和 </html>
标签之后。
enforceHtmlBoundary: true
htmlparser2 选项
sanitize-html 是基于 htmlparser2
构建的。默认情况下,唯一传递的选项是 decodeEntities: true
。你可以使用 parser 选项来设置要传递的选项。
安全注意事项:更改 parser
设置可能会有风险。 特别是,decodeEntities: false
存在已知的安全问题,并且不存在针对与 sanitize-html
一起使用的每种可能设置组合的完整测试套件。如果安全是你的目标,我们建议你使用默认值而不是更改 parser
,除了 lowerCaseTags
选项。
const clean = sanitizeHtml(dirty, {
allowedTags: ['a'],
parser: {
lowerCaseTags: true
}
});
有关可能选项的完整列表,请参阅 htmlparser2 wiki。
转换
如果你想添加或更改属性怎么办?如果你想将一个标签转换为另一个标签怎么办?没问题,很简单!
最简单的方法(将所有 ol
标签更改为 ul
标签):
const clean = sanitizeHtml(dirty, {
transformTags: {
'ol': 'ul',
}
});
最高级的用法:
const clean = sanitizeHtml(dirty, {
transformTags: {
'ol': function(tagName, attribs) {
// 在这里进行自定义处理
return {
tagName: 'ul',
attribs: {
class: 'foo'
}
};
}
}
});
你可以指定 *
通配符而不是标签名来转换所有标签。
还有一个辅助方法,对于简单情况下你想更改标签和/或添加一些属性应该足够了:
const clean = sanitizeHtml(dirty, {
transformTags: {
'ol': sanitizeHtml.simpleTransform('ul', {class: 'foo'}),
}
});
simpleTransform
辅助方法有3个参数:
simpleTransform(newTag, newAttributes, shouldMerge)
最后一个参数(shouldMerge
)默认设置为 true
。当为 true
时,simpleTransform
将当前属性与新属性(newAttributes
)合并。当为 false
时,所有现有属性都将被丢弃。
你还可以添加或修改标签的文本内容:
const clean = sanitizeHtml(dirty, {
transformTags: {
'a': function(tagName, attribs) {
return {
tagName: 'a',
text: '一些文本'
};
}
}
});
例如,你可以将缺少锚文本的链接元素:
<a href="http://somelink.com"></a>
转换为带有锚文本的链接:
<a href="http://somelink.com">一些文本</a>
过滤器
你可以提供一个过滤器函数来删除不需要的标签。假设我们需要删除空的 a
标签,如:
<a href="page.html"></a>
我们可以使用以下过滤器来实现:
sanitizeHtml(
'<p>This is <a href="http://www.linux.org"></a><br/>Linux</p>',
{
exclusiveFilter: function(frame) {
return frame.tag === 'a' && !frame.text.trim();
}
}
);
提供给回调函数的 frame
对象具有以下属性:
tag
: 标签名,例如'img'
。attribs
: 标签的属性,例如{ src: "/path/to/tux.png" }
。text
: 标签的文本内容。mediaChildren
: 可能代表自包含媒体的直接子标签(例如img
、video
、picture
、iframe
)。完整列表请参见src/index.js
中的mediaTags
变量。tagPosition
: 标签在结果字符串中的位置索引。
你还可以使用提供的过滤器函数处理所有文本内容。假设我们想要用省略号代替三个点。
<p>一些文本...</p>
我们可以使用以下过滤器来实现:
sanitizeHtml(
'<p>一些文本...</p>',
{
textFilter: function(text, tagName) {
if (['a'].indexOf(tagName) > -1) return //跳过锚标签
return text.replace(/\.\.\./, '…');
}
}
);
请注意,传递给 textFilter
方法的文本已经被转义以安全显示为HTML。你可以在 textFilter
中添加标记并使用实体转义序列。
Iframe 过滤器
如果你想允许iframe标签但想控制允许通过的域,你可以提供一个主机名数组和/或你想允许作为iframe源的域数组。这个主机名是作为参数传递给sanitize-html函数的选项对象中的一个属性。
这些数组将根据传递给函数的html进行检查,并且只返回包含对象中允许的主机名或域的 src
url。传递的html中的url必须格式正确(有效的主机名)作为嵌入式iframe,否则模块将从iframe中剥离src。
确保传递有效的主机名以及你希望允许的域,例如:
allowedIframeHostnames: ['www.youtube.com', 'player.vimeo.com'],
allowedIframeDomains: ['zoom.us']
你也可以指定是否允许相对 URL 作为 iframe 源。
allowIframeRelativeUrls: true
请注意,如果未指定,在没有提供主机名或域名过滤器的情况下,默认允许相对 URL;但如果提供了主机名或域名过滤器,则默认会移除相对 URL。
记住,iframe
标签以及 src
属性都必须被允许。
例如:
const clean = sanitizeHtml('<p><iframe src="https://www.youtube.com/embed/nykIhs12345"></iframe><p>', {
allowedTags: [ 'p', 'em', 'strong', 'iframe' ],
allowedClasses: {
'p': [ 'fancy', 'simple' ],
},
allowedAttributes: {
'iframe': ['src']
},
allowedIframeHostnames: ['www.youtube.com', 'player.vimeo.com']
});
将被视为安全通过,而:
const clean = sanitizeHtml('<p><iframe src="https://www.youtube.net/embed/nykIhs12345"></iframe><p>', {
allowedTags: [ 'p', 'em', 'strong', 'iframe' ],
allowedClasses: {
'p': [ 'fancy', 'simple' ],
},
allowedAttributes: {
'iframe': ['src']
},
allowedIframeHostnames: ['www.youtube.com', 'player.vimeo.com']
});
或
const clean = sanitizeHtml('<p><iframe src="https://www.vimeo/video/12345"></iframe><p>', {
allowedTags: [ 'p', 'em', 'strong', 'iframe' ],
allowedClasses: {
'p': [ 'fancy', 'simple' ],
},
allowedAttributes: {
'iframe': ['src']
},
allowedIframeHostnames: ['www.youtube.com', 'player.vimeo.com']
});
将返回一个空的 iframe 标签。
如果你想允许任何级别的子域名,可以在 allowedIframeDomains
中提供域名
// 这个 iframe 标记将被视为安全通过。
const clean = sanitizeHtml('<p><iframe src="https://us02web.zoom.us/embed/12345"></iframe><p>', {
allowedTags: [ 'p', 'em', 'strong', 'iframe' ],
allowedClasses: {
'p': [ 'fancy', 'simple' ],
},
allowedAttributes: {
'iframe': ['src']
},
allowedIframeHostnames: ['www.youtube.com', 'player.vimeo.com'],
allowedIframeDomains: ['zoom.us']
});
脚本过滤器
类似于 iframe,你可以在允许列表中的域名上允许脚本标签
const clean = sanitizeHtml('<script src="https://www.safe.authorized.com/lib.js"></script>', {
allowedTags: ['script'],
allowedAttributes: {
script: ['src']
},
allowedScriptDomains: ['authorized.com'],
})
你也可以在允许列表中的主机名上允许脚本标签
const clean = sanitizeHtml('<script src="https://www.authorized.com/lib.js"></script>', {
allowedTags: ['script'],
allowedAttributes: {
script: ['src']
},
allowedScriptHostnames: [ 'www.authorized.com' ],
})
允许的 URL 方案
默认情况下,我们在允许 href
、src
等的情况下允许以下 URL 方案:
[ 'http', 'https', 'ftp', 'mailto' ]
如果你想,可以覆盖这个设置:
sanitizeHtml(
// 数据 URL 中的极小有效透明 GIF
'<img src="https://raw.githubusercontent.com/apostrophecms/sanitize-html/main/data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" />',
{
allowedTags: [ 'img', 'p' ],
allowedSchemes: [ 'data', 'http' ]
}
);
你也可以只为特定标签允许一个方案:
allowedSchemes: [ 'http', 'https' ],
allowedSchemesByTag: {
img: [ 'data' ]
}
你还可以禁止使用协议相对 URL(以 //
开头)来使用当前协议访问另一个站点,默认情况下这是允许的:
allowProtocolRelative: false
丢弃不允许标签的全部内容
通常情况下,除了少数例外,如果一个标签不被允许,其中的所有文本都会被保留,允许的标签也会被保留。
例外情况是:
style
, script
, textarea
, option
如果你希望替换这个列表,例如丢弃 noscript
标签中的任何内容,请使用 nonTextTags
选项:
nonTextTags: [ 'style', 'script', 'textarea', 'option', 'noscript' ]
请注意,如果你使用这个选项,你需要负责声明整个列表。这给了你保留 textarea
内容的能力,如果你想这样做的话。
内容仍然会被正确转义,但 script
和 style
标签除外。允许 script
或 style
会使你面临 XSS 攻击的风险。除非你有充分的理由信任它们的来源,否则不要这样做。如果允许这些标签,sanitize-html 会记录一个警告,可以通过 allowVulnerableTags: true
选项禁用此警告。
选择如何处理不允许的标签
除了丢弃或只保留文本之外,你还可以启用对整个内容的转义:
disallowedTagsMode: 'escape'
这会将 <disallowed>content</disallowed>
转换为 <disallowed>content</disallowed>
有效值为: 'discard'
(默认),'completelyDiscard'
(完全移除不允许的标签的内容),'escape'
(转义标签)和 'recursiveEscape'
(递归转义标签及其所有内容)。
丢弃不允许的标签但保留其内部内容
如果你将 disallowedTagsMode
设置为 discard
,不允许的标签会被丢弃,但其内部内容会被保留。
disallowedTagsMode: 'discard'
这会将 <disallowed>content</disallowed>
转换为 content
完全丢弃不允许的标签的内容
如果你将 disallowedTagsMode
设置为 completelyDiscard
,不允许的标签及其包含的任何内容都会被丢弃。任何子标签仍然会被包含,只要这些单独的子标签是允许的。
disallowedTagsMode: 'completelyDiscard'
这会将 <disallowed>content <allowed>content</allowed> </disallowed>
转换为 <allowed>content</allowed>
转义不允许的标签及其所有子元素,即使是允许的标签
如果你将 disallowedTagsMode
设置为 recursiveEscape
,不允许的标签及其子元素将被转义,即使是允许的标签
disallowedTagsMode: `recursiveEscape`
这会将 <disallowed>hello<p>world</p></disallowed>
转换为 <disallowed>hello<p>world</p></disallowed>
忽略样式属性内容
你可以通过禁用样式属性的解析来允许有问题的样式属性,而不是丢弃它们:
parseStyleAttributes: false
这会将 <div style="invalid-prop: non-existing-value">content</div>
转换为 <div style="invalid-prop: non-existing-value">content</div>
,而不是将其剥离为 <div>content</div>
默认情况下,parseStyleAttributes 选项为 true。
当你禁用样式属性的解析(parseStyleAttributes: false
)并为 allowedStyles 属性传入选项时,将抛出错误。不允许这种组合。
我们建议在 Node.js 环境中在服务器端对内容进行清理,因为你无法信任浏览器来清理内容。考虑一个恶意用户可以通过网络面板、浏览器控制台或仅仅编写类似于你的 JavaScript 提交内容的脚本来做什么。但如果你真的需要在浏览器的客户端运行它,你可能会发现你需要禁用 parseStyleAttributes。这可能会发生变化,因为这是 postcss 的一个上游问题,而不是 sanitize-html 本身的问题。
限制深层嵌套
你可以使用 nestingLimit
选项限制文档中 HTML 标签的深度:
nestingLimit: 6
这将防止用户嵌套标签超过 6 层深。深于此的标签会被剥离,就像它们被禁止一样。请注意,这意味着在适当的情况下,文本会以通常的方式被保留。
关于 ApostropheCMS
sanitize-html 由 P'unk Avenue 为 ApostropheCMS 创建,后者是一个基于 Node.js 构建的开源内容管理系统。如果你喜欢 sanitize-html,你绝对应该看看 ApostropheCMS。
支持
欢迎在 github 上提出问题。