Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

New CSRF token per request or NOT?

Tags:

php

csrf

So I am reading around and was really confused about having a CSRF token, whetever I should generate a new token per each request, or just per hour or something?

$data['token'] = md5(uniqid(rand(), true)); $_SESSION['token'] = $data['token']; 

But let's say it's better to generate a token each hour, then I would need two sessions: token, expiration,

And how will I proceed it to the form? Just put echo $_SESSION['token'] on the hidden value form and then compare on submit?

like image 306
John Avatar asked May 05 '12 21:05

John


People also ask

Does CSRF token change for every request?

CSRF tokens are often bound to the user's session: while the user is logged in, they keep the same CSRF token. However, there are some security advantages to changing the CSRF token more often, or even on every request.

How often should a CSRF token change?

Often sessions do expire within 60 minutes, so a session based CSRF token has something like that as well (albeit it behaves a bit differently as the timeout period extends with each interaction). However, after each hour, the session id should be regenerated as well to prevent sessions that can be kept open unlimited.

Why is it necessary to always generate fresh CSRF tokens?

The purpose of having a Refreshed Laravel CSRF token is that it prevents session fixation from any web attacker, and as a result possibility of any intended CSRF attack.

Does CSRF apply to get requests?

CSRF GET RequestThe simplest CSRF attack is simply to trick a user into making a GET request to a specific URL. This can done by putting the URL into a deceptively named link. The link could be put in a blog comment (lots of WordPress exploits have used this technique), a post on a web forum, or in a phishing email.


2 Answers

If you do it per form request - then you basically remove the ability for CSRF attacks to occur & you can solve another common issue: multiple form submission

In simple terms - your application will only accept form input if the user ASKED for the form prior to the submission.

Normal scenario: User A goes to your website, and asks for Form A, is given Form A plus a unique code for Form A. When the user submits Form A, he/she must include the unique code which was only for Form A.

CSRF Attack scenario: User A goes to your website, and asks for Form A. Meanwhile they visit another "bad" site, which attempts a CSRF attack on them, getting them to submit for a fake Form B.

But your website knows that User A never asked for Form B - and therefore even though they have the unique code for Form A, Form B will be rejected, because they dont have a Form B unique Code, only a Form A code. Your user is safe, and you can sleep easy at night.

But if you do it as a generic token, lasting for an hour (like you posted above) - then the attack above might work, in which case you've not achieved much with your CSRF protection. This is because the application does not know that form B was never asked for in the first place. It is a generic token. The WHOLE POINT of CSRF prevention is to make each form token unique to that form

Edit: because you asked for more information: 1 - you dont have to do it per form request, you can do it per hour/session etc. The point is a secret value that is given to the user, and resubmiited on the return. This value is not known by another website, and thus cannot submit a false form.

So you either generate the token per request, or per session:

// Before rendering the page: $data['my_token'] = md5(uniqid(rand(), true)); $_SESSION['my_token'] = $data['my_token'];  // During page rendering: <input type="hidden" name="my_token" id="my_token" value="<? php echo $_SESSION['my_token']?>" />  // After they click submit, when checking form: if ($_POST['my_token'] === $_SESSION['my_token']) {         // was ok } else {           // was bad!!! } 

and because it is "per form" - you wont get double form submissions - because you can wipe the token after the first form submission!

like image 140
Laurence Avatar answered Oct 05 '22 22:10

Laurence


Generally, it suffices to have one single token per user or per session. It is important that the token is bound to just one particular user/session and not globally used.

If you are afraid the token could get leaked to or get obtained by an attacking site (e. g. by XSS), you can limit the token’s validity to just a certain timeframe, a certain form/URL, or a certain amount of uses.

But limiting the validity has the drawback that it might result in false positives and thus restrictions in usability, e. g. a legitimate request might use a token that just have been invalidated as the token request is too long ago or the token has already been used too often.

So my recommendation is to just use one token per user/session. And if you want further security, use one token per form/URL per user/session so that if a token for one form/URL gets leaked the others are still safe.

like image 27
Gumbo Avatar answered Oct 06 '22 00:10

Gumbo