I stand up for children in need. Please join me in helping this family.

Skip to content
Steven Roland

Implementing Per-Form CSRF Tokens in PHP

PHP , HTML

Building on our previous discussion of simple CSRF tokens, this post will focus on implementing per-form CSRF tokens in PHP. This approach enhances security by generating a unique token for each form, reducing the risk of token reuse and potential attacks.

Why Use Per-Form CSRF Tokens?

Per-form CSRF tokens provide an additional layer of security by ensuring that each form submission is uniquely validated. This method is particularly effective in mitigating the impact of token leakage, as an attacker would only be able to exploit a specific form or action.

Generating Per-Form CSRF Tokens

To implement per-form tokens, we need to generate a unique token for each form and store it in the session with a unique identifier. Here’s how you can achieve this:

1. Token Generation and Storage

For each form, generate a secure token and store it in the session with a specific key associated with the form:

session_start();

function generateFormToken($formName) {
    $token = bin2hex(random_bytes(32));
    $_SESSION['csrf_tokens'][$formName] = $token;
    return $token;
}

$formName = 'contact_form';
$token = generateFormToken($formName);

2. Embedding the Token in Forms

Include the generated token in the form as a hidden input field. This ensures that the token is sent along with the form data:

<form method="post" action="process_form.php">
    <!-- Other form fields -->
    <input type="hidden" name="csrf_token" value="<?php echo htmlspecialchars($token); ?>">
    <input type="hidden" name="form_name" value="<?php echo htmlspecialchars($formName); ?>">
    <input type="submit" value="Submit">
</form>

3. Validating the Token

Upon form submission, validate the token by checking it against the session-stored token for the specific form:

session_start();

function validateFormToken($formName, $receivedToken) {
    if (isset($_SESSION['csrf_tokens'][$formName]) && hash_equals($_SESSION['csrf_tokens'][$formName], $receivedToken)) {
        unset($_SESSION['csrf_tokens'][$formName]); // Invalidate the token after use
        return true;
    }

    return false;
}

if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    $formName = $_POST['form_name'];
    $receivedToken = $_POST['csrf_token'];

    if (validateFormToken($formName, $receivedToken)) {
        // Proceed with the action
    } else {
        // Handle invalid token
        echo "Invalid or expired token.";
    }
}

Advantages of Per-Form Tokens

  • Enhanced Security: Each form has its own token, minimizing the risk of token reuse.

  • Flexibility: Allows handling multiple forms on the same page with distinct tokens.

  • Reduced Impact of Token Leakage: Limits potential exploitation to a specific form or action.

Best Practices

  • Session Management: Ensure secure session handling to prevent session hijacking.

  • HTTPS: Use HTTPS to protect token transmission.

  • Token Expiration: Consider implementing token expiration to further enhance security.

By implementing per-form CSRF tokens, you can significantly bolster the security of your PHP applications, ensuring that each form submission is uniquely validated and protected against potential attacks.

Support My Work

If you enjoy my content, consider supporting me through Buy Me a Coffee or GitHub Sponsors.

Buy Me A Coffee
or

More posts

Navigating Beliefs: The Quest for True Meaning

Inspired by Chuck Palahniuk's quote, this post explores the challenge of believing in the right things and finding true meaning. It offers insights on critical thinking, questioning beliefs, and the importance of accurate interpretation in our quest for understanding.

How to Register Global Functions in PHP Using Composer

Learn how to register global functions in PHP using Composer. This guide covers creating a helpers file, configuring Composer, updating the autoloader, and using global functions. Best practices and tips for efficient implementation are also discussed.