如何安全地将rails模型属性传递给javascript?

时间:2012-01-27 12:10:28

标签: javascript ruby-on-rails security

我正在尝试通过html将模型属性传递给javascript:

<script type="text/javascript">
  myModel = <%= MyModel.all.map{|m| m.attributes}.to_json.html_safe %>;
</script>

但是,它不安全,因为其中一个属性值可能是恶意字符串:

"</script>Evil Code<script>"

如何让它再次安全?

2 个答案:

答案 0 :(得分:1)

在阅读你的问题后的第一秒,我认为你误解了html_safe方法的功能,我说:

  

方法html_safe具有非常误导性的名称。它不会使您的String安全,也不会逃避不安全的字符。它只是告诉它是安全的,通常与你想要的相反。

这个说明可能对某些人有用,所以请允许我留在这里。 并接受我的道歉:)

然后我开悟了真正的问题是<script>元素具有“奇怪的”逃避规则,真的很难实现。基本上,脚本元素内容不能包含</script或一些空白字符所包含的字符串>

HTML5script内容定义了一些与HTML4不同的规则。请注意,在HTML4 中,任何结束标记都显示为非法,而HTML5仅考虑</script>

问题是在脚本元素中无法识别字符实体,因此我们的任务是尝试根据JavaScript(或任何其他语言)语法规则删除禁用的子字符串。这可能很难实现自动化。

如果其中一个禁用字符串放在双引号文字中,那么我们可以用<"+"/script替换它。如果它是单引号文字,我们应该使用<'+'/script。如果它在评论中......等等。

我认为在这种情况下,我们可以假设(阅读:“祈祷并希望”)这个 script-end 总是放在双引号中,并且永远不会成为变量名称的一部分。这个简单的gsub应该适用于大多数情况:

<%= MyModel.all.map{|m| m.attributes}.
     to_json.gsub("</script", "<\"+\"/script").html_safe %>;

然而,我发现这种过度的信仰非常令人不安: - (

答案 1 :(得分:0)

我决定创建一个帮助函数,它使用h方法转义每个属性:

def safe_attributes_of model_class
  attributes = model_class.all.map do |model|
    model.attributes.each_with_object({}) do |(k,v), attrs| 
      attrs[k] = h(v)
    end
  end

  attributes.to_json.html_safe
end