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.
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.
The anti-CSRF token should be cryptographically secure.
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:
- 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().