Anti-CSRF tokens



CSRF attacks are possible because the attacker knows which request parameter values to send to the target website.

In fact, a CSRF link or redirect must provide the website with the correct parameters and values for the attack to succeed.

This fact tells us how to defend against CSRF: make sure that the attacker does NOT know all the correct parameter values.


Anti-CSRF tokens

To defend against CSRF attacks, a back-end script must be edited in order to require a security token from the user before allowing any operation.

Let's go back to the user.php example.

A new input value is added to the form. This input contains a random token created by the script.

The token is also stored inside the user's Session:

Each time the user.php page is accessed, a new random token will be created and included in the form like this:

When the form is submitted, the back-end must check that the token sent with the form matches the one saved inside $_SESSION.

If there is no match, the operation is not allowed:

The token is generated when the authenticated user accesses user.php, so there in no way for the attacker to retrieve it.

Note that the token must be included in any request sent to the server, including JavaScript and AJAX-based ones (you will find more details in the next lesson).


Pro Tip

YOU CAN ALSO STORE THE ANTI-CSRF TOKEN IN THE DATABASE IF YOU PREFER NOT TO USE SESSIONS.




Token generation

The anti-CSRF token should be cryptographically secure.

The simplest way to generate it is to use the random_bytes() and bin2hex() PHP functions.

The previous example uses a 16 bytes value, which is usually enough. However, you can also use a bigger value to reduce the risk of reply attacks:

Output:


Lesson takeaways

  • Anti-CSRF tokens are an effective defense against CSRF attacks.
  • Every request must include the dynamically generated token. If the token doesn't match, the request must be denied.
  • The token must be cryptographically secure. You can generate it with random_bytes() and bin2hex().



Discussion

22 comments