在DOM中嵌入任意JSON的最佳实践?

Ben*_*Lee 104 javascript json dom embedding decoupling

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

<script type="application/json" id="stuff">
    {
        "unicorns": "awesome",
        "abc": [1, 2, 3]
    }
</script>
Run Code Online (Sandbox Code Playgroud)

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

var stuff = JSON.parse(document.getElementById('stuff').innerHTML);
Run Code Online (Sandbox Code Playgroud)

这有效,但这是最好的方法吗?这是否违反任何最佳做法或标准?

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

Jam*_*rgy 75

我认为你原来的方法是最好的.HTML5规范甚至解决了这个用途:

"当用于包含数据块(而不是脚本)时,数据必须内联嵌入,数据格式必须使用type属性给出,不得指定src属性,并且脚本元素的内容必须符合为所用格式定义的要求."

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

你完全是这样做的.什么不爱?属性数据不需要字符编码.您可以根据需要对其进行格式化.它具有表现力,预期用途很明确.它不像是一个黑客(例如使用CSS来隐藏你的"载体"元素).这完全有效.

  • 只有在您首先检查并清理JSON对象时,它才是完全有效的:您不能只嵌入用户原始数据.看看我对这个问题的评论. (17认同)
  • 谢谢.规范的引用使我信服. (3认同)
  • 不幸的是,CSP 策略可能/将停止所有脚本` 标签。 (2认同)
  • 您如何有效地防止嵌入包含&lt;/ script&gt;并因此允许HTML注入的JSON?有什么扎实/容易的东西,还是使用数据属性更好? (2认同)

Hor*_*aan 21

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

<div id="mydiv" data-unicorns='{"unicorns":"awesome", "abc":[1,2,3]}' class="hidden"></div>
Run Code Online (Sandbox Code Playgroud)

如果你正在使用jQuery,那么检索它就像下面这样简单:

var stuff = JSON.parse($('#mydiv').attr('data-unicorns'));
Run Code Online (Sandbox Code Playgroud)

  • 但有一个问题:HTML 5中的属性长度是否有限制? (4认同)
  • 这不适用于单个字符串,例如"我是有效的JSON",并使用标记的双引号,或字符串中带单引号的单引号,例如`data-unicorns ='"My JSON的字符串"' `作为单引号不会使用JSON编码进行转义. (2认同)

小智 12

这种在脚本标记中嵌入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>
Run Code Online (Sandbox Code Playgroud)

没有办法绕过/编码.

  • 这是事实,但这并不是该方法的安全漏洞.如果您曾经将源自用户输入的内容放入您的页面中,您必须勤于逃避它.只要您采取有关用户输入的正常预防措施,此方法仍然是正确的. (6认同)

Rún*_*erg 9

HTML5 包含一个用于保存机器可读数据的<data>元素。作为 \xe2\x80\x94 也许更安全的 \xe2\x80\x94 替代方案,<script type="application/json">您可以将 JSON 数据包含在value该元素的属性中。

\n\n

\r\n
\r\n
const jsonData = document.querySelector(\'.json-data\');\r\nconst data = JSON.parse(jsonData.value);\r\n\r\nconsole.log(data)
Run Code Online (Sandbox Code Playgroud)\r\n
<data class="json-data" value=\'\r\n  {\r\n    "unicorns": "awesome",\r\n    "abc": [1, 2, 3],\r\n    "careful": "to escape &#39; quotes"\r\n  }\r\n\'></data>
Run Code Online (Sandbox Code Playgroud)\r\n
\r\n
\r\n

\n\n

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

\n


Mat*_*hew 6

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

假设您要在HTML中包含此JSON:

{
    "html": "<script>alert(\"XSS!\");</script>"
}
Run Code Online (Sandbox Code Playgroud)

<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>
Run Code Online (Sandbox Code Playgroud)

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

var text = document.querySelector('#init_data').textContent;
var json = JSON.parse(text);
console.log(json); // {html: "<script>alert("XSS!");</script>"}
Run Code Online (Sandbox Code Playgroud)


cop*_*opy 5

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

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

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