Rails:如何通过客户端AJAX请求escape_javascript

Rails: How to escape_javascript with client-side AJAX request

本文关键字:请求 escape javascript AJAX 客户端 何通过 Rails      更新时间:2023-09-26

当我通过to_json从控制器动作直接客户端发送它时,我如何逃避集合?

  • 当我说请求从控制器动作发送,然后直接到客户端(跳过预处理),它看起来像这样:

    • AJAX请求被路由到控制器动作
    • Controller Action直接通过javascript将结果发送给请求者,在客户端,请求者的javascript将进行处理。app/assets/javascripts/blogs.js
  • 这与将请求发送到controller_action,然后发送到服务器端视图进行预处理,然后将结果发送给请求者相反。如下所示:

      AJAX请求
    • 路由到控制器动作
    • 发送到视图进行预处理。app/views/blogs/index.js.erb
    • 结果被发送给请求者

简短示例:

def some_action
  @blogs = Blog.all
  respond_to do |format|
    format.json {render json: @blogs} # currently dangerous, @blogs is not sanitized.
  end
end

作为一个例子:假设该集合中的一个@blogs记录具有来自黑客的以下数据输入:

@blogs.first.title
  => <script>alert('Site now hacked if this javascript runs!')</script>

@blogs在浏览器中呈现时:我想要转义@blogs内容,以便javascript不会从被黑客入侵的条目中触发

长例子:

  • 用户在选择框中选择blogger
  • 发送一个AJAX请求,该请求捕获与所选blogger相关的所有blogs
  • 然后AJAX请求为blogs更新一个选择框,现在将列出作为选项的所有blogs的belong_to选择的blogger

对于代码:上面的控制器动作代码将完全相同。下面是客户端javascript:

应用程序/资产/javascript/blogs.js

$("body").on('change', '[data-action="blogger_sel"]', function() {
  var blogs_selection = $(this).closest('[data-parent-for="blogs_sel"]').find('[data-action="blogs_sel"]');
  $.ajax({
    url: "/blogs",
    type: "GET",
    data: {blogger_id: $(this).val()},
    success: function (data) {
      blogs_selection.children().remove();
      $.each(data, function (index, item) {
        blogs_selection.append('<option value=' + item.id + '>' + item.title + '</option>');
       });
     }
   })
 });

所以在上面:我关心的部分是value.idvalue.title。如果我不逃脱,这些东西可能会很危险。我想确保它被转义,这样任何危险的输入将被呈现为无害的

解决方案如下:请记住,在将数据持久化到数据库之前对其进行消毒通常也是一个好主意。另外:在向请求者发送响应之前,最好对服务器端进行清理:

应用程序/资产/javascript/blogs.js

$("body").on('change', '[data-action="blogger_sel"]', function() {
  var blog_sel = $(this).closest('[data-parent-for="blog_sel"]').find('[data-action="blog_sel"]');
  $.ajax({
    url: "/blogs",
    type: "GET",
    data: {blogger_id: $(this).val()},
    success: function (data) {
      blog_sel.children().remove();
      $.each(data, function (index, item) {
        blog_sel.append($('<option>', {
          value: item.id,
          text : item.title
        }));
      });
    }
  })
});

不要像那样附加选项,因为这会执行危险的攻击:

blogs_selection.append('<option value=' + value.id + '>' + value.title + '</option>');

您正在处理一个未经处理的HTML字符串。在将它插入页面之前,您需要确保它是安全的。您真正需要做的就是将<>字符替换为&lt;&gt;

以控制器为例:

class SomethingController < ApplicationController
  def jsontest
    render json: { blogs: ["<script>alert(1);</script>"] }
  end
end

jQuery可以为你做这些,如果你不介意笨重的话:

$.ajax({
  type: 'GET',
  url: '/something/jsontest', 
  dataType: 'json',
  success: function (data) { 
    console.log($('<div>').text(data['blogs'][0]).html()); 
  }
})
> &lt;script&gt;alert(1);&lt;/script&gt;

您还可以考虑在控制器端使用ActionView::Helpers::SanitizeHelper#sanitize,这将破坏它找到的任何HTML标记。(通常这只对视图可用,所以你可以在控制器中创建一个视图来呈现JSON或include ActionView::Helpers::SanitizeHelper)。或者两者都做!