Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Rails authenticity_token on a form vs csrf token

On same page of a rails 4 app I have a

in the head:

<meta name="csrf-param" content="authenticity_token" />
<meta name="csrf-token" content="some_token" />

and below in the body:

<form action="/someaction" method="post">
<input name="utf8" type="hidden" value="&#x2713;" />
<input type="hidden" name="_method" value="patch" />
<input type="hidden" name="authenticity_token" value="another_token" />

The csrf token is need for js calls. But why is the form token different from the csrf token? Which of the two tokens is used on form submission?

like image 426
kmitov Avatar asked Aug 10 '16 10:08

kmitov


People also ask

Does every form need CSRF token?

Yes, using tokens is the only way to protect reliably against CSRF attacks. Whether a protection is required or not depends on the actions the program does with the submitted data. As a rule of thumb: If data is modified with the permissions or context of the current user, you need the protection.

How does Rails protect against CSRF?

Briefly, Cross-Site Request Forgery (CSRF) is an attack that allows a malicious user to spoof legitimate requests to your server, masquerading as an authenticated user. Rails protects against this kind of attack by generating unique tokens and validating their authenticity with each submission.

What is Authenticity_token?

The authenticity token is designed so that you know your form is being submitted from your website. It is generated from the machine on which it runs with a unique identifier that only your machine can know, thus helping prevent cross-site request forgery attacks.

When should CSRF token be generated?

A CSRF Token is a secret, unique and unpredictable value a server-side application generates in order to protect CSRF vulnerable resources. The tokens are generated and submitted by the server-side application in a subsequent HTTP request made by the client.


1 Answers

I've made some researches to answer your question, and here are results.

First of all, let's look at this part:

<meta name="csrf-param" content="authenticity_token" />
<meta name="csrf-token" content="some_token" />

This part is generated by method csrf_meta_tags. From the source code we can see that:

  1. "content" attribute value of <meta name="csrf-param" /> is taken from request_forgery_protection_token, and, by default, is :authenticity_token.

  2. "content" attribute value of <meta name="csrf-token" /> is taken from form_authenticity_token method, where the token is either taken from session, or generated.

Now let's check out this part:

<input type="hidden" name="authenticity_token" value="another_token" />

From the source we can see that:

  1. This hidden input is returned by extra_tags_for_form method.
  2. Inside extra_tags_for_form invokes token_tag method.
  3. token_tag method takes the token as the argument.
  4. token argument for token_tag is previously extracted from options argument of form_tag method in html_options_for_form method.

So if you didn't manually set authenticity_token param in options to your custom token and didn't meet the conditions that lead to setting token value to false (will be mentioned below), token_tag method will receive nil and invoke the same form_authenticity_token method that is used for the <meta name="csrf-token" /> tag creating. By the way, for filling name attribute of input it also uses request_forgery_protection_token, that is used when <meta name="csrf-param" /> tag generation occurs.

And because this all occurs during the same request, invocation of form_authenticity_token method should return the same result in both cases.

Which of the two tokens is used on form submission?

On form submission will be used the token from hidden input.

Token from <meta /> also can be used, but only if all of below conditions (that make token argument of token_tag method be set to false) will be met:

  1. :remote => true should be passed in options of form_tag.
  2. embed_authenticity_token_in_remote_forms config is set to false.
  3. authenticity_token wasn't passed in options.

But why is the form token different from the csrf token?

As for this question, maybe this problem occurs because of caching. Or, probably, if you use Turbolinks gem, it might cause this issue (you can check this if you totally refresh the page and compare tokens once again). For more info about problem with Turbolinks, check this question.

like image 155
Maksim Kalmykov Avatar answered Sep 28 '22 05:09

Maksim Kalmykov