Home > Backend Development > PHP Tutorial > CSRF Protection in PHP

CSRF Protection in PHP

Patricia Arquette
Release: 2024-12-09 04:41:11
Original
343 people have browsed it

CSRF Protection in PHP

What is CSRF?

Cross-Site Request Forgery (CSRF) is a web security vulnerability that allows an attacker to trick authenticated users into executing unwanted actions on a website where they're currently logged in. The attack works by exploiting the trust that a website has in a user's browser.

How CSRF Attacks Work

  1. User logs into legitimate website A and receives a session cookie
  2. User visits malicious website B while still logged into A
  3. Website B contains code that makes a request to website A
  4. The browser automatically includes the session cookie
  5. Website A processes the request thinking it's legitimate

CSRF Protection Methods in PHP

1. Token-Based Protection Using Hidden Input

This is the most common method. Here's how to implement it:

// In your session initialization (e.g., at login)
session_start();
if (empty($_SESSION['csrf_token'])) {
    $_SESSION['csrf_token'] = bin2hex(random_bytes(32));
}

// In your form
function generateFormWithCSRFToken() {
    return '<form method="POST" action="/submit">
        <input type="hidden" name="csrf_token" value="' . $_SESSION['csrf_token'] . '">
        <!-- rest of your form fields -->
        <input type="submit" value="Submit">
    </form>';
}

// In your form processing
function validateCSRFToken() {
    if (!isset($_POST['csrf_token']) || !isset($_SESSION['csrf_token']) ||
        !hash_equals($_SESSION['csrf_token'], $_POST['csrf_token'])) {
        die('CSRF token validation failed');
    }
    return true;
}
Copy after login
Copy after login

2. CSRF Protection Using Custom Headers

This method uses AJAX requests with custom headers:

// PHP Backend
session_start();
if (empty($_SESSION['csrf_token'])) {
    $_SESSION['csrf_token'] = bin2hex(random_bytes(32));
}

// Validate the token
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    $headers = getallheaders();
    if (!isset($headers['X-CSRF-Token']) || 
        !hash_equals($_SESSION['csrf_token'], $headers['X-CSRF-Token'])) {
        http_response_code(403);
        die('CSRF token validation failed');
    }
}

// JavaScript Frontend
const csrfToken = '<?php echo $_SESSION["csrf_token"]; ?>';

fetch('/api/endpoint', {
    method: 'POST',
    headers: {
        'X-CSRF-Token': csrfToken,
        'Content-Type': 'application/json'
    },
    body: JSON.stringify(data)
});
Copy after login
Copy after login

3. Double Submit Cookie Pattern

This method involves sending the token both as a cookie and as a request parameter:

// Set both cookie and session token
session_start();
$token = bin2hex(random_bytes(32));
$_SESSION['csrf_token'] = $token;
setcookie('csrf_token', $token, [
    'httponly' => true,
    'secure' => true,
    'samesite' => 'Strict'
]);

// Validation function
function validateDoubleSubmitToken() {
    if (!isset($_COOKIE['csrf_token']) || 
        !isset($_POST['csrf_token']) || 
        !isset($_SESSION['csrf_token'])) {
        return false;
    }

    return hash_equals($_COOKIE['csrf_token'], $_POST['csrf_token']) && 
           hash_equals($_SESSION['csrf_token'], $_POST['csrf_token']);
}
Copy after login

4. SameSite Cookie Attribute

Modern applications can also use the SameSite cookie attribute as an additional layer of protection:

// Set cookie with SameSite attribute
session_start();
session_set_cookie_params([
    'lifetime' => 0,
    'path' => '/',
    'domain' => $_SERVER['HTTP_HOST'],
    'secure' => true,
    'httponly' => true,
    'samesite' => 'Strict'
]);
Copy after login

Best Practices for CSRF Protection

  1. Token Generation
    • Use cryptographically secure random number generators
    • Make tokens sufficiently long (at least 32 bytes)
    • Generate new tokens for each session
function generateSecureToken($length = 32) {
    return bin2hex(random_bytes($length));
}
Copy after login
  1. Token Validation
    • Use timing-safe comparison functions
    • Validate token presence and value
    • Implement proper error handling
function validateToken($userToken, $storedToken) {
    if (empty($userToken) || empty($storedToken)) {
        return false;
    }
    return hash_equals($storedToken, $userToken);
}
Copy after login
  1. Form Implementation
    • Include tokens in all forms
    • Implement automatic token injection
    • Handle token rotation
class CSRFProtection {
    public static function getTokenField() {
        return sprintf(
            '<input type="hidden" name="csrf_token" value="%s">',
            htmlspecialchars($_SESSION['csrf_token'])
        );
    }
}
Copy after login

Framework-Specific Protection

Many PHP frameworks provide built-in CSRF protection:

Laravel Example

// In your session initialization (e.g., at login)
session_start();
if (empty($_SESSION['csrf_token'])) {
    $_SESSION['csrf_token'] = bin2hex(random_bytes(32));
}

// In your form
function generateFormWithCSRFToken() {
    return '<form method="POST" action="/submit">
        <input type="hidden" name="csrf_token" value="' . $_SESSION['csrf_token'] . '">
        <!-- rest of your form fields -->
        <input type="submit" value="Submit">
    </form>';
}

// In your form processing
function validateCSRFToken() {
    if (!isset($_POST['csrf_token']) || !isset($_SESSION['csrf_token']) ||
        !hash_equals($_SESSION['csrf_token'], $_POST['csrf_token'])) {
        die('CSRF token validation failed');
    }
    return true;
}
Copy after login
Copy after login

Symfony Example

// PHP Backend
session_start();
if (empty($_SESSION['csrf_token'])) {
    $_SESSION['csrf_token'] = bin2hex(random_bytes(32));
}

// Validate the token
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    $headers = getallheaders();
    if (!isset($headers['X-CSRF-Token']) || 
        !hash_equals($_SESSION['csrf_token'], $headers['X-CSRF-Token'])) {
        http_response_code(403);
        die('CSRF token validation failed');
    }
}

// JavaScript Frontend
const csrfToken = '<?php echo $_SESSION["csrf_token"]; ?>';

fetch('/api/endpoint', {
    method: 'POST',
    headers: {
        'X-CSRF-Token': csrfToken,
        'Content-Type': 'application/json'
    },
    body: JSON.stringify(data)
});
Copy after login
Copy after login

Common Pitfalls to Avoid

  1. Don't use predictable tokens
  2. Don't store tokens in JavaScript variables accessible globally
  3. Don't skip CSRF protection for AJAX requests
  4. Don't rely solely on checking the Referer header
  5. Don't use the same token for multiple forms

CSRF protection is crucial for web application security. While there are multiple approaches to implementing CSRF protection, the token-based approach using hidden form fields remains the most widely used and reliable method. Remember to combine different protection methods for enhanced security and always follow security best practices when implementing CSRF protection in your PHP applications.

Remember that CSRF protection should be part of a broader security strategy that includes proper session management, secure cookie handling, and input validation.

The above is the detailed content of CSRF Protection in PHP. For more information, please follow other related articles on the PHP Chinese website!

source:dev.to
Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
Latest Articles by Author
Popular Tutorials
More>
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template