Question

I'm attempting to learn how to secure my forms with CSRF tokens, and from what I've read, I think what I am doing is secure, but I don't know enough about it to really validate that statement.

So far what I am doing is the following steps:

  1. generate a key, using openssl_random_pseudo_bytes();, and then store that key in the session. This key is generated when the session is first created.

  2. on every page encrypt the session ID with the key to generate a CSRF token, using:

    $encrypted = base64_encode(mcrypt_encrypt(MCRYPT_RIJNDAEL_256, md5($key), session_id(), MCRYPT_MODE_CBC, md5(md5($key))));
    
  3. Place that CSRF Token into a hidden input in the form.

  4. On page load check for post, if Post, decrypt CSRF Token and compare with Session_id using

    $decrypted = rtrim(mcrypt_decrypt(MCRYPT_RIJNDAEL_256, md5($key), base64_decode($encrypted), MCRYPT_MODE_CBC, md5(md5($key))), "\0");
    
  5. If the the decrypted token matches the session ID, then continue with the form, else, log the user out and redirect to main page.

My issues with this thus far are the following:

  1. Is it possible for the attacker to hijack the session and get the key? If so, does that compromise the integrity of the check, considering they won't know what I'm encrypting with said key?

  2. I know thus far nothing is vulnerable to XSS (to my knowledge), so is it possible for an attacker to get the CSRF token from a legitimate user?

  3. The way this is setup, the CSRF token is the generated only once per session, which seems not very secure, even though the session and token time out after a few hours. Should the token be generated on every page load? If so, won't this mess up a user using multiple tabs?

Any help is appreciated, I'm still trying to learn all this, and security gets much more complex than I first thought.

Was it helpful?

Solution

  1. An attacker can steal the session if there is an XSS on your app. But stealing key looks harder as it is never exposed to front-end.

  2. There might be other vulnerabilities that might result in token hijacking like insecure communication. It is always possible for tokens to be stolen.

  3. As an improvement, CSRF token can be generated again for each form. In this case, the list of generated valid CSRF tokens should be stored per user session. So that, at a given moment there might be more than one valid CSRF token for a user. This will allow users to work on multiple tabs.

You might want to read OWASP Session Management Recommendations. It is a bit long but very helpful.

I believe creating a new CSRF token for every page is a bit too much "security" compared to its benefit. In fact OWASP CSRF Prevention Cheat Sheet describes prevention using a single token per session.

Also it would be more secure to create token with one way hashing (like sha-512) instead of encrypting session ID.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top