What is CSRF and How to Implement PHP CSRF Tokens
This article explains the mechanics of Cross-Site Request Forgery (CSRF), a critical web vulnerability where unauthorized commands are transmitted from a trusted user. You will learn how CSRF attacks exploit session trust, why standard authentication fails to prevent them, and how to implement a secure, state-matching CSRF token system in PHP using cryptographically secure tokens.
What is Cross-Site Request Forgery (CSRF)?
Cross-Site Request Forgery (CSRF) is an attack that forces an end user to execute unwanted actions on a web application in which they are currently authenticated.
When a user logs into a website, the server typically establishes a session and stores a session identifier in a cookie on the user’s browser. For every subsequent request, the browser automatically attaches this cookie.
An attacker exploits this behavior by hosting a malicious website or sending a malicious link. If the authenticated user visits the attacker’s site, the site can trigger a hidden state-changing request (like changing an email address, transferring funds, or purchasing an item) to the target web application. Because the victim’s browser automatically appends the session cookies, the target application processes the request as if the legitimate user intentionally initiated it.
How CSRF Tokens Work
The most effective defense against CSRF attacks is the Synchronizer Token Pattern.
A CSRF token is a unique, secret, and unpredictable value generated by the server-side application for the user’s current session. When a state-changing action is performed (such as submitting a POST form), the application must require this token in the request payload. The server then compares the submitted token against the token saved in the user’s session. If they match, the request is deemed legitimate. Because an external malicious site cannot access the token stored in the user’s session or read the target page’s DOM due to the Same-Origin Policy, they cannot forge a valid request.
Implementing CSRF Tokens in PHP
To secure your PHP applications against CSRF, follow this three-step implementation process.
Step 1: Generate and Store the CSRF Token
First, start the session and generate a secure token if one does not
already exist. Use random_bytes() to ensure the token is
cryptographically secure.
<?php
// Start the session
if (session_status() === PHP_SESSION_NONE) {
session_start();
}
// Generate a secure token if it doesn't exist
if (empty($_SESSION['csrf_token'])) {
$_SESSION['csrf_token'] = bin2hex(random_bytes(32));
}
?>Step 2: Insert the Token into HTML Forms
Embed the generated token as a hidden input field in every state-changing HTML form (e.g., POST, PUT, DELETE requests).
<form action="process.php" method="POST">
<!-- Your form inputs -->
<label for="email">Update Email:</label>
<input type="email" id="email" name="email" required>
<!-- Hidden CSRF Token Field -->
<input type="hidden" name="csrf_token" value="<?php echo $_SESSION['csrf_token']; ?>">
<button type="submit">Submit</button>
</form>Step 3: Validate the Token on the Server
When processing the form submission, verify that the submitted token
exists and matches the token stored in the session. Use
hash_equals() to compare the tokens; this function prevents
timing attacks by comparing strings in constant time.
<?php
session_start();
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
// Check if the token exists in both the post data and the session
if (!isset($_POST['csrf_token']) || !isset($_SESSION['csrf_token'])) {
http_response_code(403);
die("Error: CSRF token missing.");
}
// Validate the token using a timing-attack safe comparison
if (!hash_equals($_SESSION['csrf_token'], $_POST['csrf_token'])) {
http_response_code(403);
die("Error: CSRF token validation failed.");
}
// Token is valid; proceed with processing the request safely
$email = filter_input(INPUT_POST, 'email', FILTER_VALIDATE_EMAIL);
echo "Success: Email updated to " . htmlspecialchars($email);
}
?>By ensuring that every state-altering request requires a matching, cryptographically secure token, you successfully mitigate the risk of Cross-Site Request Forgery in your PHP applications.