126

我正在考虑在 DOM 中嵌入任意 JSON,如下所示:

<script type="application/json" id="stuff">
    {
        "unicorns": "awesome",
        "abc": [1, 2, 3]
    }
</script>

这类似于将任意 HTML 模板存储在 DOM 中以供以后与 JavaScript 模板引擎一起使用的方式。在这种情况下,我们可以稍后检索 JSON 并解析它:

var stuff = JSON.parse(document.getElementById('stuff').innerHTML);

这行得通,但这是最好的方法吗?这是否违反任何最佳实践或标准?

注意:我不是在寻找将 JSON 存储在 DOM 中的替代方法,我已经确定这是解决我遇到的特定问题的最佳解决方案。我只是在寻找最好的方法来做到这一点。

4

7 回答 7

85

我认为您的原始方法是最好的。HTML5 规范甚至解决了这种用途:

“当用于包含数据块(相对于脚本)时,数据必须内嵌,数据的格式必须使用 type 属性给出,src 属性不能指定,脚本元素的内容必须符合为使用的格式定义的要求。”

在这里阅读:http: //dev.w3.org/html5/spec/Overview.html#the-script-element

你已经做到了。什么是不爱?无需对属性数据进行字符编码。您可以根据需要对其进行格式化。它具有表现力,预期用途很明确。感觉不像是 hack(例如使用 CSS 来隐藏你的“载体”元素)。这是完全有效的。

于 2012-02-16T23:23:36.613 回答
22

作为一般方向,我会尝试使用HTML5 数据属性。没有什么可以阻止您输入有效的 JSON。例如:

<div id="mydiv" data-unicorns='{"unicorns":"awesome", "abc":[1,2,3]}' class="hidden"></div>

如果您使用的是 jQuery,那么检索它就像这样简单:

var stuff = JSON.parse($('#mydiv').attr('data-unicorns'));
于 2012-02-16T23:03:56.987 回答
15

这种将 json 嵌入脚本标签的方法存在潜在的安全问题。假设 json 数据来自用户输入,则可以制作一个数据成员,该成员实际上会脱离脚本标签并允许直接注入 dom。看这里:

http://jsfiddle.net/YmhZv/1/

这里是注射

<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>

转义/编码是没有办法的。

于 2014-03-04T23:47:12.463 回答
7

请参阅OWASP 的 XSS 预防备忘单中的规则 #3.1

假设你想在 HTML 中包含这个 JSON:

{
    "html": "<script>alert(\"XSS!\");</script>"
}

创建一个隐藏<div>在 HTML 中。接下来,通过编码不安全的实体(例如,&、<、>、"、' 和 /)来转义您的 JSON,并将其放入元素中。

<div id="init_data" style="display:none">
        {&#34;html&#34;:&#34;&lt;script&gt;alert(\&#34;XSS!\&#34;);&lt;/script&gt;&#34;}
</div>

现在您可以通过textContent使用 JavaScript 读取元素并解析它来访问它:

var text = document.querySelector('#init_data').textContent;
var json = JSON.parse(text);
console.log(json); // {html: "<script>alert("XSS!");</script>"}
于 2018-03-02T00:47:01.467 回答
6

我建议将 JSON 放入带有函数回调(一种JSONP)的内联脚本中:

<script>
someCallback({
    "unicorns": "awesome",
    "abc": [1, 2, 3]
});
</script>

如果执行脚本在文档之后加载,您可以将其存储在某处,可能带有额外的标识符参数:someCallback("stuff", { ... });

于 2012-02-16T23:13:39.070 回答
5

HTML5 包含一个用于保存机器可读数据的<data>元素。作为一种(可能更安全)的替代方法,<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 &#39; quotes"
  }
'></data>

在这种情况下,如果您选择用双引号将值括起来,则需要用&#39;或替换所有单引号。&quot;否则,您的风险XSS攻击就像其他答案所暗示的那样。

于 2019-05-25T22:40:39.390 回答
1

我的建议是将 JSON 数据保存在外部.json文件中,然后通过 Ajax 检索这些文件。您不会将 CSS 和 JavaScript 代码放到网页上(内联),那么为什么要使用 JSON 呢?

于 2012-02-16T23:16:53.127 回答