I am learning about how to prevent CSRF using anti-CSRF tokens. Essentially, the idea is to:-
1) generate a token eg Md5 or Sha1 then store this value in a session variable:-
$token = md5(uniqid(rand(), TRUE));
$_SESSION['token'] = $token;
2) All forms include this token value in a POST hidden field
<input type='hidden' name='token' value='$nonce_token' />
Eg what it would look like to user in source code:-
<input type='hidden' name='token' value='9ee66e4e63a06ee4b83a3edde4ecd587' />
3) Once form sent check POST hidden field token value matches token stored in session value
if($_POST['token']==$_SESSION['token']){...ok...}
However, this process seems a little flawed since by including the token value in a hidden POST field an attack can simply just look at the website source code to see the token and then just include this in a malicious generated POST form which my application would thus succeed once received as token value sent would match the token value in my session variable, since I essentially show the token value in my hidden field to the attacker.
Thus, my question is what is the best way around this, as a few ideas I had still seem little flawed:-
1) Using _GET instead but this still has flaws like _POST
2) Changing the token value after x minutes or each request but causes usability issues when going back in browser or fail when user filling in form and token value would become outdated compared to updated session token value as hidden token value would not have updated whilst user filling in a form.
3) Try encrypting hidden POST form token value then decrypting on sending POST but encrypting/decrypting an already hashed value seems complicated especially one way encrypted has values like MD5 etc?
Any ideas would be much appreciated.
However, this process seems a little flawed since by including the token value in a hidden POST field an attack can simply just look at the website source code
No they can't.
Alice runs a website. Bob visits the website. Mallory is attacking Bob's account.
Bob gets a nonce token when he visits Alice's website.
If Mallory visited the site, Mallory would get a different nonce (because Mallory would have a different session).
If Mallory generated a form with malicious data in it (on her website) and tricked Bob into submitting it, then the nonce Mallory put in the form would not match the nonce in Bob's session and the submission would be rejected.
What you need to do is make the hidden field the MD5 or SHA1 hash of the session ID with a salt. That way you compare the submitted value with the hash of the session ID plus salt and if they match it is valid. If an attacker can guess the token then they have already stolen the session id and would be pointless to do anymore protecting since login has already been hijacked. It's really as simple as that. Here is some great info per OWASP on how to prevent CSRF https://www.owasp.org/index.php/Cross-Site_Request_Forgery_(CSRF)_Prevention_Cheat_Sheet
Let's review the attack scenario:
- You have a server at
example.com
and you use CSRF tokens in your forms.
- Each CSRF token is unique, specific to a user and only valid for some time.
- A malicious third party, Eve, tricks one of your users, Alice, to come to her site, attempting to mount a CSRF attack.
- If Eve simply tricks Alice into submitting a form to your server without CSRF token, your server will reject it.
- If Eve also has an account on your server and tries to get any token to submit with the form, this will fail because the token is not valid for Alice.
This leaves this scenario: Using Javascript, Eve fetches a form from your server as Alice, then submits this form back, including a valid token. I.e. Eve completely impersonates Alice for the entire process of a regular form submission using Javascript. This is prevented by the Same Origin Policy. Eve's Javascript won't be able to fetch information from your server, Alice's browser will prevent this as it violates the Same Origin Policy.
That is, assuming there are no security holes in the browser which allow Eve to circumvent that policy. This also means that you need to guard against XSS, i.e. against Eve being able to inject one of her scripts into your website, so regular visitors to your site will run Eve's scripts as part of your site, from the same origin.
As a bit of self-promotion, I've just implemented a signature based CSRF token library, which you may want to look at: Kunststube\CSRFP. I'd also like to solicit peer review and criticism of it, while I'm at it.
At first, you have to keep in mind, that you cannot prevent hackers from attacking your application, only you can make things harder.
The idea is come clearly when you thinking about what is the main goal of CSRF attacks, The CSRF is an attack that tricks the victim into loading a page that contains a malicious request. It is malicious in the sense that it inherits the identity and privileges of the victim to perform an undesired function on the victim's behalf, like change the victim's e-mail address, home address, or password, or purchase something. CSRF attacks generally target functions that cause a state change on the server but can also be used to access sensitive data.
So as above, attackers don't make attack directly to your web page, they need bridge, that's it they need a Victim, so they can use victim identity and privileges to execute actions.
when you said:
However, this process seems a little flawed since by including the token value in a
hidden POST field an attack can simply just look at the website source code
it's doesn't make sense, because attacker will not attack himself.
i hope this was help full.