为何在渲染部分图像之前先进行escape_javascript?


120

我正在看这个Railscast插曲,想知道为什么escape_javascript需要在这里致电:

$("#reviews").append("<%= escape_javascript(render(:partial => @review)) %>");

有什么escape_javascript用?

根据Rails的文档

escape_javascript(javascript)

转义符返回以及JavaScript段的单引号和双引号。

但这对我来说意义不大。


23
仅供参考,此处接受的答案不是正确的答案。Kikito是
Steve

Answers:



362

如果将代码分为两部分,则更容易理解。

第一部分$("#reviews").append("<%= ... %>");是带有erb的javascript。这意味着,<%= ... %>它将被内部返回的任何红宝石代码替换。替换的结果必须是有效的javascript,否则客户端尝试对其进行处理时将抛出错误。这就是第一件事:您需要有效的javascript

要考虑的另一件事是,ruby生成的任何内容都必须包含在带有双引号的javascript字符串内-注意周围的双引号<%= ... %>。这意味着生成的javascript将如下所示:

$("#reviews").append("...");

现在,让我们检查中的红宝石部分<%= ... %>。怎么render(:partial => @review)办?它正在呈现部分代码-这意味着它可以呈现任何类型的代码-html,css ...甚至更多的javascript!

那么,如果我们的partial包含一些简单的html(如此)会发生什么呢?

<a href="/mycontroller/myaction">Action!</a> 

还记得您的JavaScript将双引号字符串作为参数吗?如果我们简单地用<%= ... %>那个部分的代码替换,那么我们就有问题了-紧跟在href=双引号之后!JavaScript将无效:

// Without escaping, you get a broken javascript string at href
$("#reviews").append("<a href="/mycontroller/myaction">Action!</a>");

为了避免这种情况的发生,您希望转义这些特殊字符,以便不对字符串进行剪切-您需要生成此字符的东西:

<a href=\"/mycontroller/myaction\">Action!</a>

这是escape_javascript做什么的。它确保返回的字符串不会“破坏” javascript。如果使用它,将获得所需的输出:

$("#reviews").append("<a href=\"/mycontroller/myaction\">Action!</a>")

问候!


4
确实,很好的解释谢谢。我想然后使用'escape_javascript'会产生误导,因为我们实际上并没有使用它来转义实际的javascript。您可以在部分脚本中放置脚本标签,然后执行所需的任何JavaScript。
史蒂夫(Steve)

13
@Steve同意,一个更好的名字是escape_for_javascript,因为通常您会转义其他代码(例如html),以免破坏javascript。
kikito

14
escape_javascript()现在有一个更短的方法:简单j()(至少在Rails 4中)。
mjnissim 2013年

@kikito,使用此效果是否会导致我尝试呈现由远程表单组成的html部分?我试图找出原因,为什么用包含另一种将通过javascript提交的表单的javascript渲染部分文档会导致第二个请求是html而不是js。如果有时间,能否请您看看我已经发布的与此有关的问题?谢谢!我的问题
杰克·史密斯

1
@JakeSmith在您的问题中回答了
kikito 2014年

8

用户可能会发布恶意代码(恶意用户),这些代码如果不放后可能会被执行,从而允许用户控制您的应用程序。

试试这个:

<% variable = '"); alert("hi there' %>
$("#reviews").append("<%= variable %>");

不是很熟悉rails的语法,但是如果您不逃避,variable则会显示一个警告框,我认为这不是预期的行为。


8

如果您在此处查看源代码,它将更加清晰。

此功能完成以下两件事:

  1. 它将输入字符串中的字符替换为JS_ESCAPE_MAP中定义的字符

    这样做的目的是确保javascript代码正确序列化,而不会干扰嵌入它的外部字符串。例如,如果您的JavaScript字符串用双引号引起来,则字符串文字中的所有引号都必须用单引号引起来,以免破坏代码。

  2. 该函数还检查结果字符串是否为html安全。如果不是,则进行必要的转义以确保该字符串变为html安全并返回结果。

当您使用escape_javascript时,通常会动态地将其嵌入到另一个字符串或现有的html中。您需要确保这样做不会使整个页面无法呈现。

其他回应中指出了此回应的某些方面,但我希望将所有内容放在一起,包括javascript逸出和html逸出之间的区别。另外,一些响应暗示此功能有助于避免脚本注入。我认为这不是此功能的目的。例如,在您的评论中,如果您的评论具有警报(“嗨,那里”),则仅将其附加到节点将不会触发弹出窗口。您没有将其嵌入在页面加载或通过其他事件触发的函数中。仅将alert('hi there')作为您的html的一部分并不意味着它将作为javascript执行。

话虽如此,但我并不否认不可能进行脚本注入。但是要避免这种情况,在获取用户数据并将其存储在数据库中时需要采取步骤。您提供的功能和示例与呈现已保存的信息有关。

希望这对您有所帮助。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.