当前得票最高的答案有一个缺点,即从字符串中删除HTML。如果这不是您想要的(当然也不是问题的一部分),那么我建议使用正则表达式查找HTML实体(/&[^;]*;/gmi
),然后遍历匹配项并将它们转换。
function decodeHTMLEntities(str) {
if (typeof str !== 'string') {
return false;
}
var element = document.createElement('div');
return str.replace(/&[^;]*;/gmi, entity => {
entity = entity.replace(/</gm, '<');
element.innerHTML = entity;
return element.textContent;
});
}
var encoded_str = `<b>↑ CAN'T HACK ME, BRO</b>`;
var decoded_str = decodeHTMLEntities(encoded_str);
console.log(decoded_str);
关于XSS攻击:
虽然innerHTML
不会在<script>
标签中执行代码,但是可能会在on*
事件属性中运行代码,因此仅使用上述正则表达式可能会被用户传入以下字符串利用:
&<img src='asdfa' error='alert(`doin\' me a hack`)' />;
因此,在将任何<
字符放入隐藏的div元素之前,有必要将它们转换为<
。
另外,为了覆盖所有可能性,我要注意一下:在全局范围内定义的函数可以被控制台中重新定义的函数覆盖,因此重要的是要使用const
定义此函数或将其放在非全局范围内。
注意:以下示例中尝试的漏洞会使堆栈片段编辑器混淆,因为它进行预处理,所以您需要在浏览器的控制台中运行它或在自己的文件中查看结果。
var tests = [
"here's a spade: ♠!",
"&<script>alert('hackerman')</script>;",
"&<img src='asdfa' error='alert(`doin\' me a hack`)' />;",
"<b>↑ CAN'T HACK ME, BRO</b>"
];
var decoded = tests.map(decodeHTMLEntities).join("\n");
console.log(decoded);
结果是:
here's a spade: ♠!
&<script>alert('hackerman')</script>;
&<img src='asdfa' error='alert(`doin' me a hack`)' />;
<b>↑ CAN'T HACK ME, BRO</b>
escape
或URI编码字符串不同,因此这些函数无法使用。 - Marcel Korpel