rails - 对于json设计请求,“警告:无法验证CSRF令牌真实性”

时间:2012-02-20 14:40:00

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

如何检索CSRF令牌以通过JSON请求传递?

我知道所有请求类型(包括JSON / XML)的安全性Rails is checking the CSRF token

我可以放入我的控制器skip_before_filter :verify_authenticity_token,但我会失去CRSF保护(不建议:-))。

此类似(仍未被接受)answer建议

  

使用<%= form_authenticity_token %>

检索令牌

问题是如何?我是否需要先对我的任何页面进行调用以检索令牌,然后使用Devise进行真正的身份验证?或者它是一个一次性的信息,我可以从我的服务器获得然后一致地使用(直到我在服务器本身手动更改它)?

11 个答案:

答案 0 :(得分:127)

修改

在Rails 4中,我现在使用@genkilabs在下面的评论中建议的内容:

protect_from_forgery with: :null_session, if: Proc.new { |c| c.request.format == 'application/json' }

这不会完全关闭内置安全性,而是在没有CSRF令牌的情况下杀死服务器时可能存在的任何会话。


skip_before_filter :verify_authenticity_token, :if => Proc.new { |c| c.request.format == 'application/json' }

这将关闭已正确标记为json post / puts的CSRF检查。

例如,在iOS中将以下内容设置为NSURLRequest,其中“parameters”是您的参数:


[request setHTTPMethod:@"POST"];

[request setValue:@"application/json" 
       forHTTPHeaderField:@"content-type"];

[request setValue:@"application/json" 
       forHTTPHeaderField:@"accept"];

[request setHTTPBody:[NSData dataWithBytes:[parameters UTF8String] 
                                            length:[parameters length]]];

答案 1 :(得分:17)

您可以在成功登录后使用自定义标头发送CSRF令牌。

例如,将它放在你的会话#create:

response.headers['X-CSRF-Token'] = form_authenticity_token

提供CSRF令牌的示例登录响应标头:

HTTP/1.1 200 OK
Cache-Control: max-age=0, private, must-revalidate
Connection: Keep-Alive
Content-Length: 35
Content-Type: application/json; charset=utf-8
Date: Mon, 22 Oct 2012 11:39:04 GMT
Etag: "9d719d3b9aabd413c3603e04e8a3933d"
Server: WEBrick/1.3.1 (Ruby/1.9.3/2012-10-12)
Set-Cookie: [cut for readability] 
X-Csrf-Token: PbtMPfrszxH6QfRcWJCCyRo7BlxJUPU7HqC2uz2tKGw=
X-Request-Id: 178746992d7aca928c876818fcdd4c96
X-Runtime: 0.169792
X-Ua-Compatible: IE=Edge

此令牌在您再次登录之前有效,或者(如果您通过API支持,则退出)。 您的客户端可以从登录响应标头中提取和存储令牌。然后,每个POST / PUT / DELETE请求必须使用在登录时收到的值设置X-CSRF-Token标头。

使用CSRF令牌的示例POST标头:

POST /api/report HTTP/1.1
Accept: application/json
Accept-Encoding: gzip, deflate, compress
Content-Type: application/json; charset=utf-8
Cookie: [cut for readability]
Host: localhost:3000
User-Agent: HTTPie/0.3.0
X-CSRF-Token: PbtMPfrszxH6QfRcWJCCyRo7BlxJUPU7HqC2uz2tKGw=

文档:form_authenticity_token

答案 2 :(得分:16)

确实最简单的方法。不要为改变标题而烦恼。

确保您拥有:

<%= csrf_meta_tag %>

layouts/application.html.erb

只需执行隐藏的输入字段:

<input name="authenticity_token" 
       type="hidden" 
       value="<%= form_authenticity_token %>"/>

或者如果你想要一个jquery ajax帖子:

$.ajax({     
    type: 'POST',
    url: "<%= someregistration_path %>",
    data: { "firstname": "text_data_1", "last_name": "text_data2", "authenticity_token": "<%= form_authenticity_token %>" },                                                                                  
    error: function( xhr ){ 
      alert("ERROR ON SUBMIT");
    },
    success: function( data ){ 
      //data response can contain what we want here...
      console.log("SUCCESS, data="+data);
    }
});

基本上,当您发布json数据时,只需在post数据中添加一个有效的authenticity_token字段,警告就会消失......

答案 3 :(得分:4)

我以这种方式解决了这个错误:

class ApplicationController < ActionController::Base
  protect_from_forgery
  skip_before_action :verify_authenticity_token, if: :json_request?

  protected

  def json_request?
    request.format.json?
  end
end

来源: http://api.rubyonrails.org/classes/ActionController/RequestForgeryProtection.html

答案 4 :(得分:3)

令人担心的是,在Rails 3.2.3中,我们现在在production.log中收到CSRF警告,但帖子没有失败!我希望它失败,因为它保护我免受攻击。你可以在过滤btw之前用jquery添加csrf标记:

http://jasoncodes.com/posts/rails-csrf-vulnerability

答案 5 :(得分:2)

我使用了以下内容。使用include?所以,如果内容类型是application / json; charset = utf-8那么它仍在工作。

protect_from_forgery with: :null_session, if: Proc.new { |c| c.request.format.include? 'application/json' }

答案 6 :(得分:2)

This answer更好。

在任何XMLHttpRequest发送之前,您无需额外的努力(附加令牌)即可保持CSRF-TOKEN验证。没有JQuery,没有什么只是复制/粘贴和刷新。

只需添加此代码即可。

(function() {
    var send = XMLHttpRequest.prototype.send,
        token = $('meta[name=csrf-token]').attr('content');
    XMLHttpRequest.prototype.send = function(data) {
        this.setRequestHeader('X-CSRF-Token', token);
        return send.apply(this, arguments);
    };
}());

答案 7 :(得分:1)

我对以下版本的Rails有同样的问题:
    gem'rails',: git =&gt; 'git://github.com/rails/rails.git',: branch =&gt; '3-2-稳定'

我更新到3.2.2,现在一切正常。 :)
    宝石'轨道','3.2.2'

答案 8 :(得分:0)

今晚我遇到了同样的问题。 发生这种情况的原因是,当您登录时,最后一个csrf-token不再有效。 我做的是: app / views / devise / sessions / create.js.rb中的$("meta[name=csrf-token]").attr('content', '<%= form_authenticity_token %>');

现在它确实有一个有效的csrf-token :) 我希望它有所帮助

答案 9 :(得分:0)

也适用于开发/测试模式。

protect_from_forgery with: :exception unless %w(development test).include? Rails.env

此警告显示是因为您正在使用:null_session,在Rails 4.1中,如果未指定with:选项,则默认情况下会正常工作。

protect_from_forgery

答案 10 :(得分:-2)

这不是一个错误。它应该在每个非GET请求上进行检查。 https://github.com/rails/rails/issues/3041