Asked  7 Months ago    Answers:  5   Viewed   289 times

I am sending data from view to controller with AJAXand I got this error:

WARNING: Can't verify CSRF token authenticity

I think I have to send this token with data.

Does anyone know how can I do this ?

Edit: My solution

I did this by putting the following code inside the AJAX post:

headers: {
  'X-Transaction': 'POST Example',
  'X-CSRF-Token': $('meta[name="csrf-token"]').attr('content')
},

 Answers

68

You should do this:

  1. Make sure that you have <%= csrf_meta_tag %> in your layout

  2. Add beforeSend to all the ajax request to set the header like below:


$.ajax({ url: 'YOUR URL HERE',
  type: 'POST',
  beforeSend: function(xhr) {xhr.setRequestHeader('X-CSRF-Token', $('meta[name="csrf-token"]').attr('content'))},
  data: 'someData=' + someData,
  success: function(response) {
    $('#someDiv').html(response);
  }
});

To send token in all requests you can use:

$.ajaxSetup({
  headers: {
    'X-CSRF-Token': $('meta[name="csrf-token"]').attr('content')
  }
});
Tuesday, June 1, 2021
 
ammezie
answered 7 Months ago
67

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]]];
Thursday, June 3, 2021
 
altexpape
answered 7 Months ago
97

I think reading CSRF-value from DOM is not a good solution, it's just a workaround.

Here is a document form angularJS official website http://docs.angularjs.org/api/ng.$http :

Since only JavaScript that runs on your domain could read the cookie, your server can be assured that the XHR came from JavaScript running on your domain.

To take advantage of this (CSRF Protection), your server needs to set a token in a JavaScript readable session cookie called XSRF-TOKEN on first HTTP GET request. On subsequent non-GET requests the server can verify that the cookie matches X-XSRF-TOKEN HTTP header

Here is my solution based on those instructions:

First, set the cookie:

# app/controllers/application_controller.rb

# Turn on request forgery protection
protect_from_forgery

after_action :set_csrf_cookie

def set_csrf_cookie
  cookies['XSRF-TOKEN'] = form_authenticity_token if protect_against_forgery?
end

Then, we should verify the token on every non-GET request.
Since Rails has already built with the similar method, we can just simply override it to append our logic:

# app/controllers/application_controller.rb

protected
  
  # In Rails 4.2 and above
  def verified_request?
    super || valid_authenticity_token?(session, request.headers['X-XSRF-TOKEN'])
  end

  # In Rails 4.1 and below
  def verified_request?
    super || form_authenticity_token == request.headers['X-XSRF-TOKEN']
  end
Wednesday, June 9, 2021
 
JohnnyW
answered 6 Months ago
30

You can safely remove the warnings with the following:

skip_before_filter  :verify_authenticity_token

This should go into every Rails API controller that you have, or if you have a base_controller for all API controllers then put it there.

If you can also access your app through a web browser then do not put this line in the application_controller as you will be creating a security vulnerability.

It is safe to remove csrf for API calls as the particular vulnerability can only be executed through a web browser.

Update 16th December 2013

I've seen some links to this answer and some other content which suggests a clarification. An API may be vulnerable to CSRF if you use web based authentication methods to authenticate the API - e.g. sessions or cookies.

There is some good detail in Is your Web API susceptible to a CSRF exploit?.

My advice still stands for users of RestKit as user credentials are unlikely to be based on sessions or cookies but rather usernames or api keys.

If your API can be authenticated with session or cookies then you should avoid skipping : verify_authenticity_token and you should think about moving to api key based authentication.

If your API can be authenticated with a username and password that is also used to authenticate on the web there is still a potential exploit, although it is less serious as it would require the user to type in their username and password to your site in the HTTP Auth challenge box while visiting the site with the exploit. Again, for the best security you should think about moving to api key based authentication.

It's worth noting that I don't agree that you need to add :only => [:your_method] for additional protection, provided that you have isolated api controllers, your api is not mixed with your web responses and you are not using session or cookies. If these are in place you can safely add the skip_before_filter into a base_controller for your api.

Sunday, July 11, 2021
 
yosemite
answered 5 Months ago
81

EDIT >> I posted this answer in a blog post as well: http://zadasnotes.blogspot.com/2010/11/rails-3-forgery-csrf-protection-for.html [archive.org]

EDIT 2 >> This was changed in Rails 3.0.4. See follow up post here: http://zadasnotes.blogspot.com/2011/02/rails-forgery-csrf-protection-for-ajax.html [archive.org]

After researching it for a while, I decided to dig a bit into the rails code documentation to find out.

Starting here: http://api.rubyonrails.org/classes/ActionController/RequestForgeryProtection.html#method-i-form_authenticity_token

protect_from_forgery adds a before_filter on verify_authenticity_token which is shown below:

# File actionpack/lib/action_controller/metal/request_forgery_protection.rb, line 95
95:       def verify_authenticity_token
96:         verified_request? || raise(ActionController::InvalidAuthenticityToken)
97:       end

And the verified_request? is shown here:

# File actionpack/lib/action_controller/metal/request_forgery_protection.rb, line   
104:       def verified_request?
105:         !protect_against_forgery? || request.forgery_whitelisted? ||
106:           form_authenticity_token == params[request_forgery_protection_token]
107:       end

Finally request.forgery_whitelisted?:

   # File actionpack/lib/action_dispatch/http/request.rb, line 126
126:     def forgery_whitelisted?
127:       get? || xhr? || content_mime_type.nil? || !content_mime_type.verify_request?
128:     end

Notice xhr?. xmlHttpRequest is whitelisted and is not on the protect_from_forgery list. So it appears that this is by design.

After researching further on xmlHttpRequests it appears that there are restrictions on running them across domains, which makes it unnecessary to apply the csrf check on xhr.

Tuesday, August 17, 2021
 
Taha
answered 4 Months ago
Only authorized users can answer the question. Please sign in first, or register a free account.
Not the answer you're looking for? Browse other questions tagged :  
Share