我正在考虑在DOM中嵌入任意JSON,如下所示:
<script type="application/json" id="stuff">
{
"unicorns": "awesome",
"abc": [1, 2, 3]
}
</script>
这类似于可以在DOM中存储任意HTML模板以供以后与JavaScript模板引擎一起使用的方式。在这种情况下,我们稍后可以检索JSON并使用以下命令解析它:
var stuff = JSON.parse(document.getElementById('stuff').innerHTML);
This works,但这是最好的方法吗?这是否违反任何最佳做法或标准?
注意:我不是在寻找在DOM中存储JSON的替代方案,我已经确定这是我遇到的特定问题的最佳解决方案。我只是在寻找最好的方法。
答案 0 :(得分:70)
我认为你原来的方法是最好的。 HTML5规范甚至可以解决这个问题:
“当用于包含数据块(而不是脚本)时,数据 必须嵌入内联,必须使用数据格式 type属性,不能指定src属性,而且 script元素的内容必须符合要求 为使用的格式定义。“
请在此处阅读:http://dev.w3.org/html5/spec/Overview.html#the-script-element
你完全是这样做的。什么不爱?属性数据不需要字符编码。您可以根据需要对其进行格式化。它具有表现力,预期用途很明确。它不像是一个黑客(例如使用CSS来隐藏你的“载体”元素)。这完全有效。
答案 1 :(得分:20)
作为一般方向,我会尝试使用HTML5 data attributes代替。没有什么可以阻止你输入有效的JSON。例如:
<div id="mydiv" data-unicorns='{"unicorns":"awesome", "abc":[1,2,3]}' class="hidden"></div>
如果您正在使用jQuery,那么检索它就像以下一样简单:
var stuff = JSON.parse($('#mydiv').attr('data-unicorns'));
答案 2 :(得分:11)
这种在脚本标记中嵌入json的方法存在潜在的安全问题。假设json数据源自用户输入,则可以创建一个数据成员,该成员实际上会脱离脚本标记并允许直接注入dom。见这里:
这是注射
<script type="application/json" id="stuff">
{
"unicorns": "awesome",
"abc": [1, 2, 3],
"badentry": "blah </script><div id='baddiv'>I should not exist.</div><script type="application/json" id='stuff'> ",
}
</script>
无法绕过/编码。
答案 3 :(得分:5)
我建议将JSON放入带有函数回调的内联脚本中(类似JSONP):
<script>
someCallback({
"unicorns": "awesome",
"abc": [1, 2, 3]
});
</script>
如果在文档之后加载执行脚本,您可以将其存储在某处,可能还有一个额外的标识符参数:someCallback("stuff", { ... });
答案 4 :(得分:5)
请参阅OWASP的XSS预防备忘单中的Rule #3.1。
假设您要在HTML中包含此JSON:
{
"html": "<script>alert(\"XSS!\");</script>"
}
在HTML中创建隐藏的<div>
。接下来,通过编码不安全的实体(例如,&amp;,&lt;,&gt;,“,”和,/)来转义您的JSON,并将其放在元素中。
<div id="init_data" style="display:none">
{"html":"<script>alert(\"XSS!\");</script>"}
</div>
现在您可以通过使用JavaScript读取元素的textContent
并解析它来访问它:
var text = document.querySelector('#init_data').textContent;
var json = JSON.parse(text);
console.log(json); // {html: "<script>alert("XSS!");</script>"}
答案 5 :(得分:2)
我的建议是将JSON数据保存在外部.json
文件中,然后通过Ajax检索这些文件。你没有把CSS和JavaScript代码放到网页上(内联),那你为什么要用JSON呢?
答案 6 :(得分:0)
HTML5包含一个<data>
element,用于保持机器可读数据。作为<script type="application/json">
的替代(也许更安全),您可以将JSON数据包括在该元素的value
属性内。
const jsonData = document.querySelector('.json-data');
const data = JSON.parse(jsonData.value);
console.log(data)
<data class="json-data" value='
{
"unicorns": "awesome",
"abc": [1, 2, 3],
"careful": "to escape ' quotes"
}
'></data>
在这种情况下,如果您选择用双引号将值引起来,则需要用'
或"
替换所有单引号。否则,建议您像其他答案一样冒险XSS攻击。