我想要将JSON的内容存储在HTML文档的源码中,放在一个脚本标签内。
该JSON的内容取决于用户提交的输入,因此需要非常小心地对该字符串进行XSS防护。
我在这里读到了两个概念。
1. 将所有出现的</script
标签替换为<\/script
,或者在服务器端将所有</
替换为<\/
。
代码示例如下(使用Python和jinja2作为示例):
// view
data = {
'test': 'asdas</script><b>as\'da</b><b>as"da</b>',
}
context_dict = {
'data_json': json.dumps(data, ensure_ascii=False).replace('</script', r'<\/script'),
}
// template
<script>
var data_json = {{ data_json | safe }};
</script>
// js
access it simply as window.data_json object
2. 将数据编码为HTML实体编码的JSON字符串,并在客户端解码+解析。 解码参考这个回答:https://dev59.com/o3I-5IYBdhLWcg3wVWpi#34064434
// view
context_dict = {
'data_json': json.dumps(data, ensure_ascii=False),
}
// template
<script>
var data_json = '{{ data_json }}'; // encoded into HTML entities, like < > &
</script>
// js
function htmlDecode(input) {
var doc = new DOMParser().parseFromString(input, "text/html");
return doc.documentElement.textContent;
}
var decoded = htmlDecode(window.data_json);
var data_json = JSON.parse(decoded);
该方法无法使用,因为在脚本源代码中的 \"
在 JS 变量中变成了 "
。此外,它创建了一个更大的 HTML 文档,也不是真正可读的,所以如果它不意味着巨大的安全风险,我会选择第一个版本。在使用第一个版本时是否存在任何安全风险?使用
.replace('</script', r'<\/script')
来净化 JSON 编码字符串是否足够?关于此问题的参考资料:
在 HTML 属性中存储 JSON 的最佳方法?
在使用 document.write() 写入时为什么要拆分 <script> 标签?
JavaScript 字符串中的脚本标记
净化 <script> 元素内容
转义脚本标记内容中的 </ 一些关于此问题的优秀外部资源:
Flask 的 tojson 过滤器实现源代码
Rail 的 json_escape 方法的帮助文档和源代码
Django 中长达 5 年的讨论票务系统和建议的代码
<
,>
, 和&
进行 HTML 实体编码。 - PointyJSON.stringify()
和 Python 的json.dumps()
不会将/
转义为\/
。我正在寻找一种自动化的方式,可以使用脚本标签解析器来解码 JSON 或对字符串使用JSON.parse()
。在服务器端手动转义需要在客户端也进行手动操作。 - hyperknot\\
,因为它取决于实现方式(有时甚至会在版本中间更改)。