Security checklist

The handful of mistakes behind most hacked PHP sites, and CSRF tokens.

Most PHP sites that get hacked fall to the same few mistakes. Check each one before you go live.

RiskDefence
SQL injectionPrepared statements with PDO, for every query
Cross-site scripting (XSS)htmlspecialchars on everything you print that came from a user
Cross-site request forgery (CSRF)A secret token in every form that changes data
Stolen sessionsession_regenerate_id at sign-in, and secure, httponly cookies
Stored passwordspassword_hash and password_verify only
Error messagesdisplay_errors off in production; log errors instead
UploadsCheck the type, rename the file, keep it out of the web folder
Old softwareKeep PHP, WordPress and plugins updated

CSRF tokens

PHP
<?php
session_start();
$_SESSION["csrf"] ??= bin2hex(random_bytes(32));

if ($_SERVER["REQUEST_METHOD"] === "POST") {
    if (!hash_equals($_SESSION["csrf"], $_POST["csrf"] ?? "")) {
        http_response_code(403);
        exit("This form has expired. Please reload the page.");
    }
    // Safe to change data here.
}
?>
<form method="post">
  <input type="hidden" name="csrf" value="<?= htmlspecialchars($_SESSION["csrf"]) ?>">
  <button>Delete my account</button>
</form>

Another site can make a signed-in visitor's browser submit a form to yours. That site cannot read the token, so the forged request fails the check. hash_equals compares in constant time, so the token cannot be guessed from timing.

Session cookie settings

PHP
<?php
session_set_cookie_params([
    "secure" => true,     // only over HTTPS
    "httponly" => true,   // JavaScript cannot read it
    "samesite" => "Lax",  // not sent with most cross-site requests
]);
session_start();
โ† JSON APIsPHP quick reference โ†’