关于ruby:Rails 4真实性令牌

Rails 4 Authenticity Token

我在开发新的Rails4应用程序(Ruby2.0.0-p0)时遇到了一些真实性令牌问题。

在编写响应JSON的控制器(使用respond_to类方法)时,我开始执行create操作,当我尝试使用curl创建记录时,开始获取ActionController::InvalidAuthenticityToken异常。

我确定我设置了-H"Content-Type: application/json",我使用-d""设置了数据,但仍然没有运气。

我尝试使用Rails3.2(Ruby1.9.3)编写相同的控制器,但没有发现任何真实性令牌问题。我四处搜索,发现Rails4中的真实性令牌发生了一些变化。据我所知,它们不再自动插入表单中了?我想这在某种程度上影响了非HTML内容类型。

有没有什么方法可以在不需要请求HTML表单、获取真实性令牌、然后使用该令牌进行另一个请求的情况下解决这个问题?还是我完全错过了一些显而易见的东西?

编辑:我刚尝试在一个新的Rails4应用程序中创建一个新的记录,但没有改变任何东西,我遇到了同样的问题,所以我想这不是我做的事情。


我想我刚刚明白了。我更改了(新)默认值

1
protect_from_forgery with: :exception

1
protect_from_forgery with: :null_session

根据ApplicationController中的注释。

1
2
# Prevent CSRF attacks by raising an exception.
# For APIs, you may want to use :null_session instead.

您可以通过查看request_forgery_protecton.rb的源代码,或者更具体地说,查看以下行来查看差异:

在轨道3.2中:

1
2
3
4
5
6
# This is the method that defines the application behavior when a request is found to be unverified.
# By default,
ails resets the session when it finds an unverified request.
def handle_unverified_request
  reset_session
end

在轨道4中:

1
2
3
def handle_unverified_request
  forgery_protection_strategy.new(self).handle_unverified_request
end

这将调用以下内容:

1
2
3
def handle_unverified_request
  raise ActionController::InvalidAuthenticityToken
end


与其关闭CSRF保护,不如在表单中添加以下代码行

1
<%= tag(:input, :type =>"hidden", :name => request_forgery_protection_token.to_s, :value => form_authenticity_token) %>

如果您使用form_for或form_标记生成表单,那么它将自动在表单中添加上述代码行。


将以下行添加到对我有效的表单中:

1
<%= hidden_field_tag :authenticity_token, form_authenticity_token %>


我认为一般来说,只要不专门实现API,就关闭CSRF保护是不好的。

在查看ActionController的Rails4API文档时,我发现您可以关闭每个控制器或每个方法库上的伪造保护。

例如,为您可以使用的方法关闭CSRF保护

1
2
class FooController < ApplicationController
  protect_from_forgery except: :index


遇到了同样的问题。通过添加到我的控制器来修复它:

1
      skip_before_filter :verify_authenticity_token, if: :json_request?


你试过了吗?

1
 protect_from_forgery with: :null_session, if: Proc.new {|c| c.request.format.json? }


这个官方文件讨论了如何正确关闭API的伪造保护http://api.rubyonrails.org/classes/actionController/requestForgeryProtection.html


这是Rails中的一个安全功能。在表单中添加此行代码:

1
<%= hidden_field_tag :authenticity_token, form_authenticity_token %>

文档可在此处找到:http://api.rubyonrails.org/classes/actionController/requestForgeryProtection.html


这些功能是为了安全和伪造保护而添加的。
但是,为了回答您的问题,这里有一些输入。您可以在控制器名称后添加这些行。

就像这样,

1
2
class NameController < ApplicationController
    skip_before_action :verify_authenticity_token

以下是不同版本的Rails的一些线条。

轨道3

skip_before_filter :verify_authenticity_token

轨道4:

skip_before_action :verify_authenticity_token

< BR>如果您打算对所有控制器例程禁用此安全功能,则可以将应用程序的protect_from_forgery的值更改为:null_session_controller.rb文件。

就像这样,

1
2
3
class ApplicationController < ActionController::Base
  protect_from_forgery with: :null_session
end


将EDOCX1[2]添加到表单标记中


如果将jquery与rails一起使用,请注意不要允许在不验证真实性令牌的情况下输入方法。

jquery ujs可以为您管理令牌

您应该已经将它作为jquery rails gem的一部分,但是您可能需要将它包含在application.js中,

1
//= require jquery_ujs

这就是您所需要的-您的Ajax调用现在应该可以工作了

有关详细信息,请参阅:https://github.com/rails/jquery-ujs网站


我所有的测试都正常。但出于某种原因,我将环境变量设置为非测试:

1
export RAILS_ENV=something_non_test

我忘记了取消设置这个变量,因为我开始获取ActionController::InvalidAuthenticityToken异常。

在取消设置$RAILS_ENV之后,我的测试再次开始工作。


定义自己的HTML表单时,必须包含身份验证令牌字符串,出于安全原因,该字符串应发送到控制器。如果您使用Rails表单帮助器来生成真实性令牌,那么将按如下方式添加到表单中。

1
2
3
4
5
6
7
<form accept-charset="UTF-8" action="/login/signin" method="post">
 
    <input name="utf8" type="hidden" value="&#x2713;" />
    <input name="authenticity_token" type="hidden" value="x37DrAAwyIIb7s+w2+AdoCR8cAJIpQhIetKRrPgG5VA=">
 
    ...
</form>

因此,解决这个问题的方法要么是添加真实性令牌字段,要么使用Rails表单帮助器,而不是牺牲安全性等。