Rails - “警告:无法验证 CSRF 令牌的真实性”对于 json 设备请求

发布于 2025-01-07 07:31:02 字数 636 浏览 0 评论 0原文

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

我知道出于安全原因 Rails 正在检查所有请求类型(包括 JSON/XML)的 CSRF 令牌

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

这个类似的(仍未被接受)答案建议

使用 <%= form_authenticity_token %> 检索令牌

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

How can I retrieve the CSRF token to pass with a JSON request?

I know that for security reasons Rails is checking the CSRF token on all the request types (including JSON/XML).

I could put in my controller skip_before_filter :verify_authenticity_token, but I would lose the CRSF protection (not advisable :-) ).

This similar (still not accepted) answer suggests to

Retrieve the token with <%= form_authenticity_token %>

The question is how? Do I need to do a first call to any of my pages to retrieve the token and then do my real authentication with Devise? Or it is an information one-off that I can get from my server and then use consistently (until I manually change it on the server itself)?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(10

○闲身 2025-01-14 07:31:03

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

例如,将其放入 session#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

You can send the CSRF token, after a successful log-in, using a custom header.

E.g, put this in your sessions#create :

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

Sample log-in response header providing the CSRF token:

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

This Token is valid until you log-in again or (log-out if you support this through your API).
Your client can extract and store the token from the log-in response headers. Then, each POST/PUT/DELETE request must set the X-CSRF-Token header with the value received at the log-in time.

Sample POST headers with the CSRF token:

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=

Documentation: form_authenticity_token

兰花执着 2025-01-14 07:31:03

确实是最简单的方法。不必费心更改标题。

确保你有:

<%= 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 数据时,只需添加一个有效的authenticity_token 字段添加到 post 数据中,并且警告应该消失......

Indeed simplest way. Don't bother with changing the headers.

Make sure you have:

<%= csrf_meta_tag %>

in your layouts/application.html.erb

Just do a hidden input field like so:

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

Or if you want a jquery ajax post:

$.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);
    }
});

Basically when you post your json data just add a valid authenticity_token field to the post data and the warning should go away...

陌路终见情 2025-01-14 07:31:03

我这样解决了该错误:

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

I resolved that error this way:

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

Source:
http://api.rubyonrails.org/classes/ActionController/RequestForgeryProtection.html

橘香 2025-01-14 07:31:03

令人担忧的是,在 Rails 3.2.3 中,我们现在在 production.log 中收到 CSRF 警告,但发布并没有失败!我希望它失败,因为它可以保护我免受攻击。您可以在过滤器之前使用 jquery 添加 csrf 令牌:

http://jasoncodes.com/posts/ Rails-csrf-漏洞

What's worrying is that in Rails 3.2.3 we now get the CSRF warning in production.log but the post does not fail! I want it to fail as it protects me from attacks. And you can add the csrf token with jquery before filter btw:

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

固执像三岁 2025-01-14 07:31:03

我用过下面的。使用包含?因此,如果内容类型是 application/json;charset=utf-8 那么它仍然有效。

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

I have used the below. Using include? so if the content type is application/json;charset=utf-8 then it is still working.

protect_from_forgery with: :null_session, if: Proc.new { |c| c.request.format.include? 'application/json' }
情话已封尘 2025-01-14 07:31:03

这个答案更好。

在发送任何 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);
    };
}());

This answer is better.

You get to keep the CSRF-TOKEN validation with no extra effort (the token is appended) before any XMLHttpRequest send. No JQuery, no nothing just copy/paste and refresh.

Simply add this code.

(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);
    };
}());
是伱的 2025-01-14 07:31:03

我在使用以下版本的 Rails 时遇到了同样的问题:
gem 'rails', :git =>; 'git://github.com/rails/rails.git', :branch => “3-2-stable”

我更新到了 3.2.2,现在一切正常。 :)
gem 'rails', '3.2.2'

I had the same issue with the following version of Rails:
gem 'rails', :git => 'git://github.com/rails/rails.git', :branch => '3-2-stable'

I updated to 3.2.2 and everything works fine for me now. :)
gem 'rails', '3.2.2'

自此以后,行同陌路 2025-01-14 07:31:03

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

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

I ran into the same issue tonight.
The reason that happens is because when you sign in the last csrf-token is no longer valid.
What I did was:
$("meta[name=csrf-token]").attr('content', '<%= form_authenticity_token %>'); in your app/views/devise/sessions/create.js.rb.

Now it does have a valid csrf-token :)
I hope it helps

遮云壑 2025-01-14 07:31:03

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

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

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

protect_from_forgery

Also for development/test mode.

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

This warning shows because you are using :null_session, in Rails 4.1 it works by default if no with: options specified.

protect_from_forgery
玩心态 2025-01-14 07:31:02

编辑

在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 posts/puts 的 CSRF 检查。

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


[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]]];

EDIT:

In Rails 4 I now use what @genkilabs suggests in the comment below:

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

Which, instead of completely turning off the built in security, kills off any session that might exist when something hits the server without the CSRF token.


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

This would turn off the CSRF check for json posts/puts that have properly been marked as such.

For example, in iOS setting the following to your NSURLRequest where "parameters" are your 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]]];
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文