如何使用 Nunjucks 安全地将 JSON 渲染为内联 <script>?
How to safely render JSON into an inline <script> using Nunjucks?
我们有一个服务器端呈现的 HTML 页面,其中包含一个外部 JavaScript 文件。要触发该文件中的代码,我们要调用一个函数并向其传递一些动态数据(以 JSON 的形式):
<script src="/static/foo/bar.js"></script>
<script>
foo.bar.init({biz: 42, qux: "quux"});
</script>
我们从 Nunjucks 模板渲染它,并在上下文中将 JSON 对象作为值 data
传递。这可以包含任意数据,包括用户提供的内容。
这是安全的但不起作用,因为 <>&
正在被转义(感谢 Nunjucks 自动转义):
foo.bar.init({{ data | dump }});
这可行,但不安全,因为 JSON 中的字符串可能包含文本 </script>
:
foo.bar.init({{ data | dump | safe }});
如何说服 Nunjucks 渲染这个 JSON 以便安全正确地解释它?听起来这应该是一个已解决的问题,但我在任何地方都找不到预制的解决方案。
暂时这样做:
/**
* Returns a JSON stringified version of the value, safe for inclusion in an
* inline <script> tag. The optional argument 'spaces' can be used for
* pretty-printing.
*
* Output is NOT safe for inclusion in HTML! If that's what you need, use the
* built-in 'dump' filter instead.
*/
env.addFilter('json', function (value, spaces) {
if (value instanceof nunjucks.runtime.SafeString) {
value = value.toString()
}
const jsonString = JSON.stringify(value, null, spaces).replace(/</g, '\u003c')
return nunjucks.runtime.markSafe(jsonString)
})
用法:
<script src="/static/foo/bar.js"></script>
<script>
foo.bar.init({{ data | json }});
</script>
仍然欢迎更好的解决方案。
我们有一个服务器端呈现的 HTML 页面,其中包含一个外部 JavaScript 文件。要触发该文件中的代码,我们要调用一个函数并向其传递一些动态数据(以 JSON 的形式):
<script src="/static/foo/bar.js"></script>
<script>
foo.bar.init({biz: 42, qux: "quux"});
</script>
我们从 Nunjucks 模板渲染它,并在上下文中将 JSON 对象作为值 data
传递。这可以包含任意数据,包括用户提供的内容。
这是安全的但不起作用,因为 <>&
正在被转义(感谢 Nunjucks 自动转义):
foo.bar.init({{ data | dump }});
这可行,但不安全,因为 JSON 中的字符串可能包含文本 </script>
:
foo.bar.init({{ data | dump | safe }});
如何说服 Nunjucks 渲染这个 JSON 以便安全正确地解释它?听起来这应该是一个已解决的问题,但我在任何地方都找不到预制的解决方案。
暂时这样做:
/**
* Returns a JSON stringified version of the value, safe for inclusion in an
* inline <script> tag. The optional argument 'spaces' can be used for
* pretty-printing.
*
* Output is NOT safe for inclusion in HTML! If that's what you need, use the
* built-in 'dump' filter instead.
*/
env.addFilter('json', function (value, spaces) {
if (value instanceof nunjucks.runtime.SafeString) {
value = value.toString()
}
const jsonString = JSON.stringify(value, null, spaces).replace(/</g, '\u003c')
return nunjucks.runtime.markSafe(jsonString)
})
用法:
<script src="/static/foo/bar.js"></script>
<script>
foo.bar.init({{ data | json }});
</script>
仍然欢迎更好的解决方案。