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

IT技术 javascript json dom embedding decoupling
2021-03-06 18:16:56

我正在考虑在 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);

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

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

6个回答

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

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

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

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

仅当您首先检查和清理 JSON 对象时它才完全有效:您不能只嵌入用户原始数据。请参阅我对这个问题的评论。
2021-04-28 18:16:56
不幸的是,CSP 政策似乎可能/将停止所有script标签。
2021-05-06 18:16:56
额外的疑惑:什么是放置它的好地方?头部或身体,顶部或底部?
2021-05-07 18:16:56
您如何有效地防止嵌入包含 </script> 的 JSON,从而允许 HTML 注入?有什么可靠/简单的东西,还是使用数据属性更好?
2021-05-07 18:16:56
谢谢你。规范中的引述说服了我。
2021-05-19 18:16:56

作为一个总体方向,我会尝试使用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'));
是的,那会奏效。您也可以切换它,以便您的 HTML 使用单引号,而 JSON 数据使用双引号。
2021-04-30 18:16:56
但有一个问题:HTML 5 中的属性长度是否有任何限制?
2021-05-02 18:16:56
说得通。但是请注意,键名使用单引号JSON.parse将不起作用(至少本机 Google Chrome JSON.parse 不会)。JSON 规范需要双引号。但这很容易使用像...&lt;unicorns&gt;:....
2021-05-04 18:16:56
好的,找到了我的问题的答案:stackoverflow.com/questions/1496096/...——这对于我的目的来说已经足够了。
2021-05-05 18:16:56
这不适用于单个字符串,例如"I am valid JSON",对标签使用双引号,或在字符串中使用带单引号的单引号,例如data-unicorns='"My JSON's string"'因为单引号不会通过编码为 JSON 进行转义。
2021-05-09 18:16:56

这种在脚本标签中嵌入 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>

没有办法转义/编码。

这是真的,但这并不是该方法的真正安全缺陷。如果您曾经将源自用户输入的内容放入您的页面,您必须努力避免它。只要您对用户输入采取正常的预防措施,这种方法仍然有效。
2021-04-21 18:16:56
JSON 不是 HTML 的一部分,HTML 解析器一直在运行。这与 JSON 成为文本段落或 div 元素的一部分时相同。HTML 转义程序中的内容。此外,您还可以转义斜线。虽然 JSON 不需要这样做,但它确实可以容忍不需要的斜杠。可以将其用于使其安全嵌入的目的。默认情况下,PHP 的 json_encode 会执行此操作。
2021-04-23 18:16:56

请参阅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>"}
我相信这是最好和最安全的答案。请注意,许多常见的 JSON 字符被转义,某些字符被双重转义,例如 object 中的内部引号{name: 'Dwayne "The Rock" Johnson'}但最好还是使用这种方法,因为您的框架/模板库可能已经包含了一种安全的 HTML 编码方式。另一种方法是使用 base64,它既是 HTML 安全的,也可以安全地放入 JS 字符串中。使用 btoa()/atob() 在 JS 中编码/解码很容易,而且您可能很容易在服务器端进行编码/解码。
2021-05-02 18:16:56
更安全的方法是使用语义正确的<data>元素并在value属性中包含 JSON 数据然后,&quot如果您使用双引号将数据括起来,或者&#39;如果您使用单引号(这可能更好),您只需要转义引号。
2021-05-19 18:16:56

我建议将 JSON 放入带有函数回调(类型JSONP的内联脚本中

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

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

这感觉更好,因为您不需要 dom 查询来查找数据
2021-04-26 18:16:56
@BenLee 它应该工作得很好,唯一的缺点是必须定义回调函数。另一个建议的解决方案会中断特殊的 HTML 字符(例如 &)和引号,如果您的 JSON 中有这些字符的话。
2021-05-04 18:16:56
这似乎会更快,因为对象被直接解析为 JavaScript,而不是从 DOM 获取文本并通过JSON.parse. 在我的网站上,我做const MY_DATA = ....
2021-05-13 18:16:56
@copy 此解决方案仍然需要转义(只是一种不同的类型),请参阅 MadCoder 的回答。只是为了完整起见把它放在这里。
2021-05-14 18:16:56