dev3 ·
I have a plain PHP site without a framework. Forms post to update profile data and delete items. How do I implement CSRF tokens correctly with sessions?
0
DEV3 Developer Forum
Every post is reviewed first. Usually reviewed within 24 hours.
I have a plain PHP site without a framework. Forms post to update profile data and delete items. How do I implement CSRF tokens correctly with sessions?
A CSRF attack makes a logged in user's browser send a state-changing request to your site from another site. The defence is a secret, per-session token that the attacker cannot read.
Generate and store the token
session_start();
function csrf_token(): string
{
if (empty($_SESSION['csrf'])) {
$_SESSION['csrf'] = bin2hex(random_bytes(32));
}
return $_SESSION['csrf'];
}
function csrf_check(?string $token): void
{
if (!is_string($token) || !hash_equals($_SESSION['csrf'] ?? '', $token)) {
http_response_code(419);
exit('Invalid CSRF token');
}
}
Put it in forms
<form method="post" action="/profile.php">
<input type="hidden" name="csrf" value="<?= htmlspecialchars(csrf_token(), ENT_QUOTES) ?>">
...
</form>
Verify on every POST, PUT, DELETE
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
csrf_check($_POST['csrf'] ?? null);
// proceed
}
For fetch/AJAX send the token in a header (X-CSRF-Token) and read it with $_SERVER['HTTP_X_CSRF_TOKEN'].
Additional layers
SameSite=Lax (or Strict), Secure and HttpOnly. SameSite alone blocks most cross-site POSTs, but keep tokens for defence in depth./delete.php?id=5 can be triggered by an image tag. Use POST plus a token.hash_equals() to compare, to avoid timing leaks.session_regenerate_id(true)).Pitfalls
Origin or Referer header too if you want extra protection on sensitive actions.