Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Generating CSRF tokens for multiple forms on a single page

Tags:

security

csrf

I am currently generating a CSRF token in my forms to prevent cross-site request forgery. It looks like:

<form method="post" action="action.php">
   <input type="hidden" id="security_token" name="security_token" value="gTt96phAcretR99rafEjepHebrEZadEdezadagaZ3gAS5es33WReJeZaMADU2AWr" />
   ...
</form>

The problem is that I have multiple forms on a single page. Must I create a security token for each form so security_token_1, security_token_2, or can I simply instead of generating the security token inside of forms, append it to a property to the entire body tag like:

<body data-csrf-token="gTt96phAcretR99rafEjepHebrEZadEdezadagaZ3gAS5es33WReJeZaMADU2AWr">
...
</body>

Is this insecure in any way? It simplifies things quite a bit, since I can simply append the security token to the body element instead of dealing with multiple security tokens.

Thanks for the insight and comments.

like image 658
Justin Avatar asked Feb 05 '13 19:02

Justin


People also ask

Can a CSRF token be used more than once?

The CSRF token sent in the state parameter is the "client side" of your usual CSRF token (the one you put in a hidden input field on your forms). Since the CSRF token will (by design) be sent in GET requests, it's advisable to make them unique and not reuse them.

How CSRF tokens are generated?

The CSRF token values contain significant entropy and are unpredictable since the generated tokens use a pseudo-random number generator, a static secret, and a seeded timestamp. In addition to this, tokens are different for each user and are stored only for an active user session.

Is it safe to store CSRF token in cookie?

Storing the CSRF Token Value in the DOM It can also be stored in a JavaScript variable or anywhere on the DOM. However, it is not recommended to store it in cookies or browser local storage.

How do I add a CSRF token?

CSRF tokens are secrets and should be handled as such in a secure manner throughout their lifecycle. Place the field containing the CSRF token as early as possible within the HTML file. Place the field that contains the token before any non-hidden fields and before any places where user-controllable data is embedded.


2 Answers

There really isn't any reason you can't have the same generated token for both forms, with each hidden field in each form having the same name attribute.

After all, what you are really trying to validate is that a form request is inbound from a user with a valid session, and only one form is going to be actively posted at a time. Thus you are comparing the token posted against a token stored in session for the user. There need not be more than one token value in order to do this.

For your case of needing to update the tokens based on AJAX posts, what you would need to do is, as you say, pass the newly created token back in the AJAX response, then update the hidden field values to the new token value.

like image 51
Mike Brant Avatar answered Sep 21 '22 03:09

Mike Brant


As long as you make sure that attackers cannot get the CSRF token (e.g. don't include it in forms that go to third parties), using a single CSRF token should be OK. Note that with your "put it into the body" method, you will need JavaScript to submit the forms, so you may still want to insert it into every form even if you use just one central token.

The OWASP Guide says:

In general, developers need only generate this token once for the current session. After initial generation of this token, the value is stored in the session and is utilized for each subsequent request until the session expires.

i.e. there is no need to use more than one token at all.

Using separate tokens just has the advantage that if you somehow managed to compromise some, but not all of them (pretty unlikely, because for example XSS will compromise all of them), the attacker's options would be limited.

like image 34
Jan Schejbal Avatar answered Sep 22 '22 03:09

Jan Schejbal