Как безопасно встроить JSON с </script> в HTML-документ? - PullRequest
20 голосов
/ 26 августа 2011

Как в приложении Rails 3.1 как безопасно встраивать некоторые данные JSON в документ HTML?

Предположим, у меня есть это в действии контроллера:

@tags = [
    {name:"tag1", color:"green"}, 
    {name:"</script><b>I can do something bad here</b>", color:"red"}
]

И это в соответствующем представлении:

<script type="text/javascript" charset="utf-8">
    //<![CDATA[
    var tags_list = <%= @tags.to_json %>;
    // ]]>
</script>

Тогда я получаю это в результате HTML:

var tags_list = [
    {&quot;name&quot;:&quot;tag1&quot;,&quot;color&quot;:&quot;green&quot;},
    {&quot;name&quot;:&quot;&lt;/script&gt;&lt;b&gt;I can do something bad here&lt;/b&gt;&quot;,&quot;color&quot;:&quot;red&quot;}
];

, который запускает SyntaxError: Unexpected token & в Chrome

Если я удаляю HTML-код Rails по умолчанию, экранирующий <%=raw tags.to_json %>, он возвращает это:

var tags_list = [
    {"name":"tag1","color":"green"},
    {"name":"</script><b>I can do something bad here</b>","color":"red"}
];

, что, конечно, разбивает HTML-документ на </script>.

Могу ли я как-то сказать методу to_json () вернуть что-то вроде этого:

var tags_list = [
    {"name":"tag1","color":"green"},
    {"name":"&lt;/script&gt;&lt;b&gt;I can do something bad here&lt;/b&gt;","color":"red"}
];

Я задал этот вопрос в списке рассылки rubyonrails-talk, и теперь я понимаю, что некоторые люди думают, что это очень плохая идея для начала, но в моем случае это работает очень хорошо, если в HTML нет специальных символов данные. Поэтому я просто хочу, чтобы строка, возвращаемая to_json HTML, была безопасной, и при этом JavaScript должен ее правильно обрабатывать.

UPDATE: Основываясь на комментарии @coreyward, я сделал его строковым литералом JS, и теперь это, похоже, работает отлично. Это не такое элегантное решение, как я надеялся, но и не так уж плохо. Вот код, который работает для меня:

<% tags = [{name:"tag1", color:"green"}, {name:"</script><b>I can \n\ndo something bad here</b>", color:"red"}] %>

<script type="text/javascript" charset="utf-8">
    //<![CDATA[
    var tags_list = $.parseJSON('<%=j tags.to_json.html_safe %>');
    // ]]>
</script>

, что приводит к:

<script type="text/javascript" charset="utf-8">
    //<![CDATA[
    var tags_list = $.parseJSON('[{\"name\":\"tag1\",\"color\":\"green\"},{\"name\":\"<\/script><b>I can \\n\\ndo something bad here<\/b>\",\"color\":\"red\"}]');
    // ]]>
</script>

Ответы [ 4 ]

8 голосов
/ 18 октября 2011

Ваш код, использующий только @tags.to_json, работает в rails3, , если , вы включаете его с помощью:

   ActiveSupport.escape_html_entities_in_json = true

В противном случае, ваш другой вариант:

   var tags_list = <%= raw @tags.to_json.gsub("</", "<\\/") %>;

Это избавляет клиента от необходимости анализировать все через $

2 голосов
/ 01 октября 2011

Кстати, это работает, но, на мой взгляд, не является хорошим решением:

<script type="text/javascript" charset="utf-8">
  //<![CDATA[
  var tags_list = <%=raw @tags.to_json.gsub('/', '\/') %>;
  // ]]>
</script>
1 голос
/ 14 января 2019

Правильный способ в 2019 году - обернуть obj.to_json с помощью функции json_escape.json_escape непосредственно предназначен для экранирования определенных символов HTML внутри строк JSON.Пример ниже из документации:

json = JSON.generate({ name: "</script><script>alert('PWNED!!!')</script>"})
# => "{\"name\":\"</script><script>alert('PWNED!!!')</script>\"}"

json_escape(json)
# => "{\"name\":\"\\u003C/script\\u003E\\u003Cscript\\u003Ealert('PWNED!!!')\\u003C/script\\u003E\"}"

JSON.parse(json) == JSON.parse(json_escape(json))
# => true

Кажется, эта страница появляется в верхней части результатов поиска Google, поэтому я решил предоставить комментарий с обновлением:)

1 голос
/ 07 октября 2011

Я думаю, что если вы попробуете это, это сработает:

var tags_list = "<%== @tags.to_json.gsub('/', '\/') %>";

(обратите внимание на двойные == и "")

...