如何将数据从Node / Express服务器传递到客户端(JavaScript),同时允许清理HTML但阻止XSS?

时间:2017-10-30 21:24:48

标签: javascript html express xss html-sanitizing

将数据从快速后端传递到客户端(JavaScript)的最佳方法是什么?这样可以使用某种客户端呈现在DOM中呈现数据,同时允许已清理的白名单HTML并仍然阻止XSS?

比方说,节点响应呈现方法如下所示:

res.render('index', {
    data : {
        foo: '<a href="myhomepage">foo</p>'
    }
}); 

无论出于何种原因,它都包括未转义的角色。通常将它包含在html / ejs模板中将是微不足道的,例如:

<script>
    myVar = JSON.parse('<%- JSON.stringify(data) %>');
</script> 

但它在锚标记的第一个双引号上扼杀:Unexpected token h in JSON at position 18

我们绝对希望允许带有HTML字符的字符串(粗体,锚链接等等)但是想要删除脚本标记和其他此类危险标记。

有没有简单的方法来实现这一目标?或者是否必须遍历传递给render方法的所有数据级别,并通过某种XSS清理程序引擎运行所有字符串键?

1 个答案:

答案 0 :(得分:0)

如果您需要允许某些不受信任的html,则可以使用外部库对其进行清理。我没有使用它,但评论中提到的DOMPurify看起来不错。在将myVar的内容添加到DOM之前,可以在服务器或客户端上完成此操作。

另一个问题是将数据从服务器传输到客户端。这有一个单独的问题。 JSON.stringify生成一个JavaScript字符串,但会解析两次。一次通过浏览器中的JavaScript引擎,加载脚本时,再由JSON.parse加载。这导致转义引号在到达JSON.parse之前未被转义,并且它以错误的方式解释它们。

如果data是:

{ foo: '<a href="myhomepage">foo</p>' }

然后JSON.stringify会产生:

{"foo":"<a href=\"myhomepage\">foo</p>"}

这将插入到html页面中,成为:

myVar = JSON.parse('{"foo":"<a href=\"myhomepage\">foo</p>"}');

此处\"序列被JavaScript解析器解释为引号,因此它与以下内容相同:

myVar = JSON.parse('{"foo":"<a href="myhomepage">foo</p>"}');

现在,href引号被解释为属性的紧密引号,而不是属性的开放引号。

你可以解决这个问题,但JSON.parse还有另一个问题。它不考虑任何周围的HTML上下文。因为它是 在<script>标记内,如果数据是:

{ foo: '</script><script>alert(1)</script>' }

它将生成HTML:

<script>
    myVar = JSON.parse('{"foo":"</script><script>alert(1)</script>"}');
</script>

这包含有效的JavaScript字符串。它不会从字符串中转义,而是直接从脚本标记中转义,并使用新脚本重新进入,从而导致XSS问题。

相反,你需要一些东西来逃避HTML和JS元字符。这样的事情应该做:

myVar = JSON.parse(unescape('<%- escape(JSON.stringify(data)) %>'));