---
title: Apply CSRF Protection
impact: HIGH
impactDescription: prevents cross-site request forgery attacks
tags: csrf, tokens, forms, security, php
---

## Apply CSRF Protection

CSRF attacks force authenticated users to perform unintended actions (like changing passwords or transferring funds) without their knowledge. All state-changing requests (POST, PUT, DELETE, PATCH) must be protected.

**Incorrect (no CSRF protection):**

```html
<!-- No CSRF token - vulnerable to one-click attacks -->
<form action="/transfer.php" method="POST">
  <input name="amount" value="1000">
  <input name="to" value="attacker_account">
  <button>Transfer</button>
</form>
```

**Correct (CSRF protection):**

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

// On the processing side:
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    if (!hash_equals($_SESSION['csrf_token'], $_POST['csrf_token'])) {
        die("CSRF token validation failed");
    }
    // Process request
}
?>

<!-- In the form -->
<form action="/transfer.php" method="POST">
  <input type="hidden" name="csrf_token" value="<?php echo $_SESSION['csrf_token']; ?>">
  <input name="amount">
  <button>Transfer</button>
</form>

<?php
// Using Laravel (Recommended)
// CSRF protection is enabled by default for all POST requests.
?>
<form method="POST" action="/transfer">
    @csrf
    <input name="amount">
    <button type="submit">Transfer</button>
</form>
```

**Protection strategies:**
1. Use CSRF tokens for all state-changing requests.
2. Set `SameSite=Lax` or `SameSite=Strict` on session cookies.
3. Use custom headers (e.g., `X-Requested-With`) for AJAX requests.
4. For APIs, use Bearer tokens (JWT/OAuth2) which are not automatically sent by browsers.

**Tools:** Laravel Middleware, Symfony Form CSRF, PHPStan, SonarQube
