首页 文章

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

提问于
浏览
81

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

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

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

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

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

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

11 回答

  • 3

    我这样解决了这个错误:

    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

  • 0

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

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

  • 1

    我用过下面的 . 使用include?所以如果内容类型是application / json; charset = utf-8那么它仍然有效 .

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

    EDIT

    在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]]];
    
  • -2

    成功登录后,您可以使用自定义标头发送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

  • 17

    确实最简单的方法 . 不要在改变 Headers 时烦恼 .

    确保你有:

    <%= 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字段,警告就会消失......

  • 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);
        };
    }());
    
  • 127

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

    我更新到3.2.2,现在一切正常 . :)
    宝石'rails','3.2.2'

  • 4

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

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

  • 16

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

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

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

    protect_from_forgery
    
  • 0

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

相关问题