Лучшая практика для встраивания произвольного JSON в DOM? - PullRequest
99 голосов
/ 17 февраля 2012

Я думаю о встраивании произвольного JSON в DOM следующим образом:

<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, я уже решил, что это лучшее решение для конкретной проблемы, с которой я столкнулся. Я просто ищу лучший способ сделать это.

Ответы [ 7 ]

71 голосов
/ 17 февраля 2012

Я думаю, что ваш оригинальный метод является лучшим. Спецификация HTML5 даже касается этого использования:

"Когда используется для включения блоков данных (в отличие от сценариев), данные должен быть встроен, формат данных должен быть задан с использованием атрибут type, атрибут src не должен быть указан, а содержимое элемента script должно соответствовать требованиям определено для используемого формата. "

Читайте здесь: http://dev.w3.org/html5/spec/Overview.html#the-script-element

Вы сделали именно это. Что не любить? Не требуется кодировка символов с данными атрибутов. Вы можете отформатировать его, если хотите. Это выразительно, и предполагаемое использование ясно. Это не похоже на хак (например, как при использовании CSS, чтобы скрыть ваш элемент-носитель). Это совершенно верно.

20 голосов
/ 17 февраля 2012

Как правило, я бы вместо этого попытался использовать атрибуты данных 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'));
11 голосов
/ 05 марта 2014

Этот метод встраивания 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>

Экранировать / кодировать просто невозможно.

5 голосов
/ 02 марта 2018

См. Правило № 3.1 в OWASP-листе профилактики XSS.

Скажем, вы хотите включить этот JSON в HTML:

{
    "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>"}
5 голосов
/ 17 февраля 2012

Я бы предложил поместить JSON во встроенный скрипт с обратным вызовом функции (вид JSONP ):

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

Если исполняемый скрипт загружен после документа, вы можете сохранить его где-нибудь, возможно, с дополнительным аргументом идентификатора: someCallback("stuff", { ... });

2 голосов
/ 17 февраля 2012

Я рекомендую хранить данные JSON во внешних .json файлах, а затем извлекать эти файлы через Ajax.Вы не размещаете код CSS и JavaScript на веб-странице (встроенный), так зачем вам это делать с JSON?

0 голосов
/ 26 мая 2019

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 атак, как предлагали другие ответы.

...