我正在尝试通过html将模型属性传递给javascript:
<script type="text/javascript">
myModel = <%= MyModel.all.map{|m| m.attributes}.to_json.html_safe %>;
</script>
但是,它不安全,因为其中一个属性值可能是恶意字符串:
"</script>Evil Code<script>"
如何让它再次安全?
答案 0 :(得分:1)
在阅读你的问题后的第一秒,我认为你误解了html_safe
方法的功能,我说:
方法
html_safe
具有非常误导性的名称。它不会使您的String安全,也不会逃避不安全的字符。它只是告诉它是安全的,通常与你想要的相反。
这个说明可能对某些人有用,所以请允许我留在这里。 并接受我的道歉:)
然后我开悟了真正的问题是<script>
元素具有“奇怪的”逃避规则,真的很难实现。基本上,脚本元素内容不能包含</script
或一些空白字符所包含的字符串>
。
HTML5为script
内容定义了一些与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