如何在rails应用程序之间传递CSRF令牌

时间:2012-02-04 13:48:48

标签: ruby-on-rails ruby-on-rails-3 csrf

我们的rails3应用程序与作为REST函数公开的另一个rails应用程序进行通信。在对REST服务进行的所有POST调用中,迁移到rails3后会收到以下警告。

WARNING: Can't verify CSRF token authenticity

当我们对REST服务进行POST调用时,我们应该如何在线路上传递csrf令牌,ApplicationController具有protect_from_forgery方法,并且该调用也会落在handle_unverified_request调用上。我们使用HTTP basic auth进行身份验证,它似乎工作正常。我们该怎么做才能解决这个问题。

1 个答案:

答案 0 :(得分:11)

好的,现在我会试一试回答你的问题。

CSRF令牌是“会话相关的”,这意味着用户必须与正在与之通信的应用程序共享会话。这意味着必须在提交实际表单之前提出请求,这是标准HTML表单的情况,表单在提交之前显示,因此可以为该用户生成CSRF令牌。

让我们调用提供UI按钮App1的应用程序和托管REST服务App2的应用程序。

用户与App1共享会话并获取App1提供的UI按钮。一旦用户单击该按钮,就会向App1发出请求,App1向App2的REST服务发出请求。

结论:用户不与App2共享会话,但您的App1与App2会话。最后有两件事:

  1. 用户不容易受到App2上的跨站点伪造的影响,因为他在该服务器上没有会话。因此,如果我在这里发布类似<img src="http://app2.com/rest-service/destroy>的内容,App2将无法识别我,因为我没有与App2共享会话而且没有任何反应。

  2. 您可以在REST服务上实施自己的安全措施,以保护它免受公众的侵害:

    • 通过HTTP Basic Auth进行身份验证
    • 通过API密钥进行身份验证
    • ....
  3. 这意味着您可以在REST服务上删除CSRF保护并保持安全,只要用户无法通过AJAX等直接进行呼叫。

    <强>加成

    CSRF保护您的网站不受来自您的来源的提交表单(实际上这仅适用于POSTed表单,因为它们通常操纵数据。

    最大的情况是:我是攻击者,我想将您的用户帐户名称更新为“Potatoe先生”,我的方式就是在我的网站上放置一个隐藏的表单,然后将其发布到Yourdomain.com/account有一个隐藏字段account[name]="Mr. Potatoe"。现在没有CSRF保护会发生什么?我的浏览器提交表单,并用它发送身份验证cookie,我的名字现在是“Potatoe先生”。 CSRF保护会发生什么?我的浏览器提交表单并发送cookie,但表单没有CSRF令牌,因此请求被拒绝。现在有没有办法让攻击者在这些情况下获得CSRF令牌?答案是不。也许你问自己......

    • 如果我在我的网站上放置一个隐藏的iframe,指向Yourdomain.com/account/edit并只复制包含该令牌的隐藏字段,该怎么办? - 答案:由于相同的原始政策,它无法正常工作,如果iframe的内容不是来自您的域名,则无法读取iframe内的内容。

    • 如果我在后台进行AJAX调用以获取令牌怎么办?答:它不起作用,因为使用纯AJAX你也必须遵守相同的原始政策。

    现在让我们谈谈:我无法从我的页面向您发送隐藏的AJAX调用,以伤害我网站上的用户。

    这是什么意思?您可以实现一个前置过滤器,用于检查request.xhr?是否为真,或者用户代理是否类似于“我的REST客户端XY”,因为这不能通过&gt;&gt;浏览器&lt;&gt;中的跨站点请求来伪造。 &LT ;.因此,如果是这种情况,您可以忽略/禁用CSRF保护。

    顺便说一下,如果你想在你的站点中发出一个AJAX请求,你可以得到这样的CSRF令牌:

    var token = $('meta[name="csrf-token"]').attr('content');
    

    请参阅Rails UJS脚本:https://github.com/rails/jquery-ujs/blob/master/src/rails.js#L81

    注意:这只能保护您免受跨站点伪造和其他任何行为....