如何在HTML文档中安全地使用</ script>嵌入JSON?

nnc*_*nnc 21 json ruby-on-rails html-parsing ruby-on-rails-3

在Rails 3.1应用程序中,如何安全地将一些JSON数据嵌入到HTML文档中?

假设我在控制器动作中有这个:

@tags = [
    {name:"tag1", color:"green"}, 
    {name:"</script><b>I can do something bad here</b>", color:"red"}
]
Run Code Online (Sandbox Code Playgroud)

这在相应的观点中:

<script type="text/javascript" charset="utf-8">
    //<![CDATA[
    var tags_list = <%= @tags.to_json %>;
    // ]]>
</script>
Run Code Online (Sandbox Code Playgroud)

然后我得到这个结果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;}
];
Run Code Online (Sandbox Code Playgroud)

这会SyntaxError: Unexpected token &在Chrome中触发

如果我删除Rails的默认HTML转义<%=raw tags.to_json %>,则返回:

var tags_list = [
    {"name":"tag1","color":"green"},
    {"name":"</script><b>I can do something bad here</b>","color":"red"}
];
Run Code Online (Sandbox Code Playgroud)

当然,这会破坏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"}
];
Run Code Online (Sandbox Code Playgroud)

我在rubyonrails-talk邮件列表上问过这个问题,我现在明白有些人认为这是一个非常糟糕的想法,但在我的情况下,只要数据中没有HTML特殊字符,它就能很好地工作.所以我只想让to_jsonHTML 返回的字符串安全,并且仍然可以正确地解析它.

更新: 基于@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>
Run Code Online (Sandbox Code Playgroud)

这导致:

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

小智 8

您的代码只能@tags.to_json在rails3中使用,如果您启用它:

   ActiveSupport.escape_html_entities_in_json = true
Run Code Online (Sandbox Code Playgroud)

否则,你的另一个选择是:

   var tags_list = <%= raw @tags.to_json.gsub("</", "<\\/") %>;
Run Code Online (Sandbox Code Playgroud)

这节省了客户端必须通过$解析整个事情


小智 8

2019年正确的做法是obj.to_jsonjson_escape功能来包裹。json_escape直接用于转义 JSON 字符串中的特定 HTML 符号。以下示例来自文档:

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

看来此页面出现在 Google 搜索结果的顶部,这就是为什么我决定提供更新的评论:)


Jor*_*ugh 2

顺便说一句,这可行,但在我看来不是一个好的解决方案:

<script type="text/javascript" charset="utf-8">
  //<![CDATA[
  var tags_list = <%=raw @tags.to_json.gsub('/', '\/') %>;
  // ]]>
</script>
Run Code Online (Sandbox Code Playgroud)