State changes without a CSRF token

State changes without a CSRF token

Description

When browsers automatically send credentials such as cookies, allowing password changes, deletions or updates without CSRF protection may let an attacker send unwanted requests with the user’s permissions.

Potential impact

Account settings, data or permissions may be changed against the user’s wishes.

Remediation

Restrict state changes to POST/PUT/DELETE and validate a CSRF token bound to the server session. Changing the HTTP method alone does not prevent CSRF.

Examples

These excerpts change an authenticated user’s password. $userId comes from the server session, not the request, and $hash is a server-generated password hash. Session initialization and error handling are omitted. checkToken() is an omitted application function that must reject missing or invalid tokens and stop processing.

Before

php
<?php
if (isset($_GET['Change'])) {
    $stmt = $db->prepare('UPDATE users SET password = ? WHERE user_id = ?');
    $stmt->bind_param('si', $hash, $userId);
    $stmt->execute();
}

After

php
<?php
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
    http_response_code(405);
    exit;
}

checkToken($_POST['user_token'] ?? '', $_SESSION['session_token'], 'index.php');
$stmt = $db->prepare('UPDATE users SET password = ? WHERE user_id = ?');
$stmt->bind_param('si', $hash, $userId);
$stmt->execute();

Explanation:

  • Before: Changes a password through a GET request without validating a CSRF token.
  • After: Requires POST and checks a session-bound CSRF token before the update. The HTTP method restriction alone would not prevent CSRF.

References