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

如何检索 CSRF 令牌以便与 JSON 请求一起传递?

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

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

这个类似的(仍然不接受) 回答建议

<%= form_authenticity_token %>检索令牌

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

87981 次浏览

我对下面的 Rails 版本也有同样的问题:
Gem‘ ails’,: git = > ‘ git:// github.com/rails/rails.git’,: Branch = >’3-2-stable’

我更新到3.2.2,现在一切都很好。 :)
Gem‘ ails’,’3.2.2’

编辑:

在 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/put 的 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]]];

令人担忧的是,在 Rails 3.2.3中,我们现在在 production.log 中得到了 CSRF 警告,但是这篇文章并没有失败!我希望它失败,因为它能保护我免受攻击。你可以在过滤之前用 jquery 添加 csrf 令牌:

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

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

例如,把这个放进你的课程 # 创造:

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 _ enticity _ token 表格 _ 真实性 _ 令牌

确实是最简单的方法,不用费心去改变标题。

确保你有:

<%= 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数据添加一个有效的 really _ token 字段,警告就会消失... ..。

我今晚也遇到了同样的问题。 发生这种情况的原因是,当您在最后一个 csrf 标记中签名时,该标记不再有效。 我所做的是: 应用程序/视图/设计/会话/create.js.rb 中的 $("meta[name=csrf-token]").attr('content', '<%= form_authenticity_token %>');

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

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

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

此警告显示,因为您正在使用 :null_session,在 Rails 4.1中,如果没有指定 with:选项,则默认情况下它可以工作。

protect_from_forgery

如果内容类型是 application/json; charset = utf-8,那么它仍然可以工作。

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

我是这样解决这个错误的:

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

这个回答 更好。

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