Rails 4 Authenticity Token

Rails 4 Authenticity Token

I think I just figured it out. I changed the (new) default

protect_from_forgery with: :exception

to

protect_from_forgery with: :null_session

as per the comment in ApplicationController.

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

You can see the difference by looking at the source for request_forgery_protecton.rb, or, more specifically, the following lines:

In Rails 3.2:

# This is the method that defines the application behavior when a request is found to be unverified.
# By default, \Rails resets the session when it finds an unverified request.
def handle_unverified_request
reset_session
end

In Rails 4:

def handle_unverified_request
forgery_protection_strategy.new(self).handle_unverified_request
end

Which will call the following:

def handle_unverified_request
raise ActionController::InvalidAuthenticityToken
end

Rails 4. How to add authenticity_token to forms rendered via partial?

In your case, we have two ways to do:

  1. Add authenticity_token: true in form options

  2. Manually add authenticity_token field into form, like this:

<%= hidden_field_tag :authenticity_token, form_authenticity_token -%>

Invalid authenticity token in Rails

I fixed this by clearing my cookie for localhost.

I had used SSH tunneling via a localhost port to access the production site, so a cookie based on a conflicting session and secret_key_base was in the localhost domain.

I prevented this from occurring again by prepending the Rails environment to the name of the cookie:

Rails.application.config.session_store :cookie_store, key: "_incidents_#{Rails.env}_session"

So that despite using localhost to access my development and production environments, they would be writing to different cookies by virtue of being in different environments.

Understanding the Rails Authenticity Token

What happens

When the user views a form to create, update, or destroy a resource, the Rails app creates a random authenticity_token, stores this token in the session, and places it in a hidden field in the form. When the user submits the form, Rails looks for the authenticity_token, compares it to the one stored in the session, and if they match the request is allowed to continue.

Why it happens

Since the authenticity token is stored in the session, the client cannot know its value. This prevents people from submitting forms to a Rails app without viewing the form within that app itself.
Imagine that you are using service A, you logged into the service and everything is OK. Now imagine that you went to use service B, and you saw a picture you like, and pressed on the picture to view a larger size of it. Now, if some evil code was there at service B, it might send a request to service A (which you are logged into), and ask to delete your account, by sending a request to http://serviceA.example/close_account. This is what is known as CSRF (Cross Site Request Forgery).

If service A is using authenticity tokens, this attack vector is no longer applicable, since the request from service B would not contain the correct authenticity token, and will not be allowed to continue.

API docs describes details about meta tag:

CSRF protection is turned on with the protect_from_forgery method,
which checks the token and resets the session if it doesn't match what
was expected. A call to this method is generated for new Rails
applications by default.
The token parameter is named authenticity_token by default. The name
and value of this token must be added to every layout that renders
forms by including csrf_meta_tags in the HTML head.

Notes

Keep in mind, Rails only verifies not idempotent methods (POST, PUT/PATCH and DELETE). GET request are not checked for authenticity token. Why? because the HTTP specification states that GET requests is idempotent and should not create, alter, or destroy resources at the server, and the request should be idempotent (if you run the same command multiple times, you should get the same result every time).

Also the real implementation is a bit more complicated as defined in the beginning, ensuring better security. Rails does not issue the same stored token with every form. Neither does it generate and store a different token every time. It generates and stores a cryptographic hash in a session and issues new cryptographic tokens, which can be matched against the stored one, every time a page is rendered. See request_forgery_protection.rb.

Lessons

Use authenticity_token to protect your not idempotent methods (POST, PUT/PATCH, and DELETE). Also make sure not to allow any GET requests that could potentially modify resources on the server.


Check the comment by @erturne regarding GET requests being idempotent. He explains it in a better way than I have done here.

Rails 4 authenticity token - both in header and form hidden input?

Browsing SO on another issue led me to the answer. In short, Rails helps out jQuery users by inserting the CSRF token into ajax requests automatically. It looks for it in the meta tags.

So having the CSRF token inside the form is useful for when submitting POST requests and having it in the head is useful for saving time/effort/mistakes with ajax requests.

Perhaps it's good to have it in both also because you may want to do an ajax request when there isn't a form present. If there IS a form and javascript is disabled, having it in the header doesn't do anyone any favours as it won't be included in the POST request.

As to why they are different, I can only guess it has something to do with the algorithm at the time of generation...but that's neither here nor there as both tokens work.

Rails Authenticity Token not valid when using a different layout

Since you are using Rails-ujs, you can use it's ajax method that already handles the token for you:

https://github.com/rails/rails/blob/master/actionview/app/assets/javascripts/rails-ujs/utils/ajax.coffee#L15

$(document).on("click",".clickable", function(){
var link = this.dataset.link;
console.log(link);
Rails.ajax({
url: link,
type: "POST",
});
});

Rails 4 Login/Sign up using devise during form submission authenticity token error

I think I fixed it with some simple jQuery code. I basically needed to replace the existing authenticity token on the parent form with the new one after sign in. Previously had enabled the Devise session method to respond to js format and had the file /devise/sessions/create.js.erb.

On the same file I had to append the following jQuery code to replace the existing authenticity token on the form with the new one generated after logging in.

$("input[name='authenticity_token'").val("<%= form_authenticity_token %>");


Related Topics



Leave a reply



Submit