关于csrf:Rails:csrf_meta_tag如何工作?

Rails: How Does csrf_meta_tag Work?

我是一个PHP开发人员,通过阅读MichaelHartl的教程来学习RubyonRails。这是这本书的引述,参考csrf_meta_tag

...the Rails method csrf_meta_tag [prevents] cross-site request
forgery (CSRF), a type of malicious web attack. Don’t worry about the
details (I don’t); just know that Rails is working hard to keep your
application secure.

问题是,我真的很好奇。插入csrf-paramcsrf-token元标签如何防止CSRF?我试着用谷歌搜索,但找不到任何东西。


csrf_meta_tag基本上实现了与隐藏表单字段相同的功能,但是否可以为不绑定到表单的javascript请求提供一种获取令牌的简单方法。

如果使用jquery ujs库,则会自动将该元标记的内容(作为请求头)添加到所发出的任何Ajax请求中。


csrf_meta_tag在页面中插入本质上是数字签名的内容,作为验证进入应用服务器的请求实际上来自正确登录的用户的验证。这有助于防止跨站点脚本(一个完全不相关的页面上的脚本在您在另一个选项卡中登录到您的Gmail时触发请求,例如gmail)。

我想澄清一下,csrf_meta_tag本身并不阻止无关页面向您的gmail(或任何其他攻击目标服务)发出请求,但csrf_meta_tag中的"数字签名"用于验证所述请求的有效性。无效请求(即来自跨站点脚本尝试的请求)应无法通过验证,因此将被丢弃。

换一种说法,从攻击者的角度来看:

csrf_meta_tags存在之前(它们不以任何方式被Rails独占),成功的跨站点脚本攻击允许恶意站点以一种方式向Web应用提交数据,使请求看起来像是以用户的名义执行的。所以,假设您是Web服务的管理员,并且在一个浏览器选项卡中,您登录到该服务的管理面板。如果在另一个选项卡中打开的恶意站点针对您的服务进行攻击,则该恶意站点可能能够运行发出管理请求的脚本,例如从数据库中转储用户列表、窃取其他敏感数据,或者在出现时(从服务器的观点)是管理者自己的有效请求。csrf_meta_tag是签署请求的一种方式,有助于阻止此类尝试的成功。

这里有更详细的解释。

在一个Rails生成的页面上执行"查看源代码"也是有教育意义的,您将看到CSRF标签是什么样子的。


在轨道上,它会像这样工作

1
2
3
4
5
6
7
8
9
def csrf_meta_tags
    if protect_against_forgery?
      [
        tag('meta', :name => 'csrf-param', :content => request_forgery_protection_token),
        tag('meta', :name => 'csrf-token', :content => form_authenticity_token)
      ].join("
").html_safe
    end
  end

查看更多详细信息只需点击

您还需要检查Ruby on Rails安全指南

这是一个不错的博客

但是-我更喜欢国家脆弱性数据库,这是很好的解释

CWE-352:跨站点请求伪造(CSRF)

CWE-79:网页生成过程中输入的中和不当("跨站点脚本")。

检查此文档中的CWE-常见缺陷枚举


csrf_meta_tags表示Ajax请求使用这些作为向服务器发出请求的表单参数之一。Rails希望CSRF作为表单主体(params)的一部分来处理您的请求。使用这些元标记,您可以构建表单主体或CSRF头以满足您的需求。我希望这个答案对你的问题有所帮助。


助手csrf_meta_标记的输出:

1
2
<meta name="csrf-param" content="authenticity_token" />
<meta name="csrf-token" content="J/gw2ePXHS9Z1SUSSeUQgMmPhsPEFlFbMrLTLFHLfKjeWh7g4uyOnBlfKnlZlmCBiALDWdDWCSo1z0tybGVtfA==" />

这个令牌可以包含在Ajax请求中。示例(jquery ujs):

https://github.com/rails/jquery-ujs/blob/4b6e30f68ff1244fc0c790641d3408c2695a29bd/src/rails.js l70

1
2
3
4
5
6
7
8
9
10
11
12
13
14
    csrfToken: function() {
     return $('meta[name=csrf-token]').attr('content');
    },

    // URL param that must contain the CSRF token
    csrfParam: function() {
     return $('meta[name=csrf-param]').attr('content');
    },

    // Make sure that every Ajax request sends the CSRF token
    CSRFProtection: function(xhr) {
      var token = rails.csrfToken();
      if (token) xhr.setRequestHeader('X-CSRF-Token', token);
    },