I have a function for my script which will generate the CSRF token for the form and then display the template. The problem I have is that 1 out of say 10 tries will throw “Token Invalid”. Could this be caused by the fact that I set my token for the session inside a function?
Are you using your browsers back button? This could cause it.
I don’t see any issue in the code you posted. But, other possibilities exist. I would do some logging. Sprinkle you code with some debugging statments that log some info to a file. For example, log the location in the code where you’re calling displayLogin(). log the time with it. log the values of the token in the session, and the value that was posted. Do you get more log entries than expected?
Off Topic:
You also need to verify that $_SESSION[‘token’] actually has a value before comparing to the posted value. Otherwise your security is easily defeated.
As far as I understand CSRF mechanism, protection needed only for users who already logged in.
And, also, it does not need regeneration during session. One token per session would be enough.
What do you mean by “session inside a function”?
A session is a session, it does not make any difference if you call it inside a function.
The reason for this maybe that you regenerating the new value of token on every page load, so if user opens a second browser window, (maybe you have a popup windows), then the token in his first opened window automatically becomes invalid
What you should do is to add an extra check
if(empty($_SESSION[‘token’]){
$sToken = generateToken();
It seems to happen as a freak occurrence when I constantly batter the form with different attempts. I haven’t implemented a bunch of logging yet to dig deeper as I want to first analyize these other responses as I might not need CSRF on a login form from the sounds of it.
Very interesting. Maybe I’m mistaken on the use of CSRF. I totally understand it’s use for action handled via GET such as http://example.com/delete/user/jdoe . So for a login form would with SQL injection protection be sufficient or should I consider other avenues of protection for the login as well?
So this extra check is ensuring that a user gets one token per session until they login and or successfully complete the action that the token is generated? Would you want to regenerate this token say after they successfully delete a user?
I believe my question now is if CSRF is a bit overkill for a login form. Thoughts?
Understood, I was merely using GET as an example since a lot of CSRF topics I have read talk about that being a primary area for it to be used as those are commonly exploited. Personally I don’t use GET for anything that manipulates or interacts directly with a database.
Which is trivial to implement, and doesn’t hinder non-supporting browsers that I think it probably worth implementing that check together with CSRF tokens.
I read an article found in your first link and so let me see if I am following correctly. You are suggesting a stateless approach by using a cookie to store the CSRF token on the client side and at the same time putting the same token in the form. Then on the server side checking to see if that CSRF token in the cookie matches the one stored in the form?
So would then pairing a stateless approach with a SSL backed website be a good layer of security? I know this won’t prevent someone which access to that users machine from getting the information but I would think it would cover most scenarios of a remote attacker trying to break in. Thoughts? Any other ways they could get in? I already cover XSS attacks in my code just need to get the CSRF protection implemented.
Rather than generating a random token, you can use
function generateToken($secret)
{
return hash_hmac('sha256', session_id(), $secret);
}
And each form|controller has it’s own secret. So when displaying a form using its secret with generateToken() to generate the CSRF token, and validate when it has been submitted.
This means can omit storing the token in the $_SESSION.
Sorry but I’m a bit confused now. I’m trying to put this all together and I’ve managed to get myself stuck. So in my below code how would I go about getting the token back into the redisplayed form that shows up when a login fails? Would I just generate a new token and then reset the cookie?
Should I have a user reenter their password on an incomplete form error? Such as if they forget to put in the username but enter a password, should I then refill in the password for them? I was thinking no.
To forge a request an attacker would need to know both the session_id of the intended victim, and the application secret key.
The session_id is in a cookie, but as your initial CSRF protection used the cookie indirectly (setting $_SESSION[‘token’]) its no more insecure than that.
If your site has a XSS (Cross site scripting) vulnerability then the CSRF protection can be bypassed, as the attacker can access CSRF token value, and post directly.
PS:
After a successful login, it is recommended that you use session_regenerate_id() to generate a new session_id. Avoiding session fixation attacks. And will invalidate any previously generated CSRF tokens with the old session.