为什么要在渲染部分之前使用 escape_javascript?

IT技术 javascript ruby-on-rails
2021-01-31 11:50:46

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

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

是什么escape_javascript用的?

根据Rails 文档

escape_javascript(javascript)

JavaScript 段的转义载体返回和单引号和双引号。

但这对我来说意义不大。

4个回答

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

第一部分$("#reviews").append("<%= ... %>");是带有 erb 的 javascript。这意味着<%= ... %>将被其内部的 ruby​​ 代码返回的任何内容替换。该替换的结果必须是有效的 javascript,否则在客户端尝试处理它时会抛出错误。所以这是第一件事:你需要有效的 javascript

另一件要考虑的事情是,无论 ruby​​ 生成什么,都必须包含在带有双引号的 javascript 字符串中——注意<%= ... %>. 这意味着生成的 javascript 将如下所示:

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

现在让我们检查<%= ... %>. 有什么作用render(:partial => @review)它正在呈现部分代码 - 这意味着它可以呈现任何类型的代码 - html、css ...甚至更多的 javascript!

那么,如果我们的部分包含一些简单的 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>")

问候!

@kikito,使用此效果是否会尝试呈现包含远程表单的 html 部分?我试图找出为什么用 javascript 渲染包含另一个将通过 javascript 提交的表单的部分会导致第二个请求是 html 而不是 js。如果你有时间,你能看看我已经发布的关于这个的问题吗?谢谢!我的问题
2021-03-19 11:50:46
@JakeSmith 回答了你的问题
2021-03-21 11:50:46
确实,非常好的解释谢谢。我想然后使用 'escape_javascript' 有点误导,因为我们实际上并没有使用它来逃避实际的 javascript。您可以在部分中放置一个脚本标记并执行您想要的任何 javascript。
2021-03-31 11:50:46
@Steve 同意,更好的名称是escape_for_javascript,因为您通常会转义其他代码(例如 html),以免破坏 javascript。
2021-04-02 11:50:46
escape_javascript()现在有一个更短的方法:simpley j()(至少在 Rails 4 中)。
2021-04-04 11:50:46

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

试试这个:

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

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

如果你看看这里的源代码,它会清楚得多。

该函数完成以下两件事:

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

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

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

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

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

也就是说,我并不否认脚本注入是不可能的。但是为了避免这种情况,您需要在获取用户数据并将其存储在数据库中时采取措施。您提供的函数和示例与呈现已保存的信息有关。

我希望这会有所帮助并回答您的问题。

因为您不希望用户发布浏览器实际执行的 JavaScript?

但是当你想要传递和呈现 javascript 代码时呢?
2021-03-14 11:50:46
是的,实际上它更像是一种格式化方法。它不会阻止用户执行他们自己的 javascript。没有什么可以阻止这一点。
2021-03-19 11:50:46
这没有帮助。请参阅kikito 的答案
2021-03-22 11:50:46