CSRF Protection

Easy

Verifies CSRF token implementation on forms and APIs.

Estimated fix time: 10 minutes

What is CSRF Protection?

Cross-Site Request Forgery (CSRF) is an attack that forces authenticated users to execute unwanted actions. Laravel provides built-in CSRF protection through tokens that verify each request originates from your application.

Security Impact

Severity: High

  • Unauthorized actions performed as legitimate users
  • Account takeover
  • Data modification or deletion
  • Privilege escalation
  • Financial fraud

How to Fix

1. Ensure CSRF Middleware is Active

// app/Http/Kernel.php
protected $middlewareGroups = [
    'web' => [
        // ... other middleware
        \App\Http\Middleware\VerifyCsrfToken::class,
    ],
];

2. Add CSRF Token to Forms

{{-- Blade template --}}
<form method="POST" action="/profile">
    @csrf
    <input type="text" name="name">
    <button type="submit">Update</button>
</form>

3. Configure AJAX Requests

// resources/js/app.js
// Add CSRF token to all AJAX requests
document.addEventListener('DOMContentLoaded', function() {
    const token = document.querySelector('meta[name="csrf-token"]').content;
    
    // Using Fetch API
    fetch('/api/endpoint', {
        method: 'POST',
        headers: {
            'X-CSRF-TOKEN': token,
            'Content-Type': 'application/json',
        },
        body: JSON.stringify(data)
    });
    
    // Using Axios (auto-configured)
    axios.post('/api/endpoint', data);
});
{{-- Add meta tag in layout --}}
<meta name="csrf-token" content="{{ csrf_token() }}">

4. Configure Axios (Automatic)

// resources/js/bootstrap.js
window.axios = require('axios');
window.axios.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest';

// CSRF token automatically added
let token = document.head.querySelector('meta[name="csrf-token"]');
if (token) {
    window.axios.defaults.headers.common['X-CSRF-TOKEN'] = token.content;
}

5. Exclude Routes from CSRF (Use Carefully)

// app/Http/Middleware/VerifyCsrfToken.php
protected $except = [
    'stripe/*', // Webhook routes
    'api/*',    // API routes (use Sanctum instead)
];

Verification Steps

  1. Submit a form without @csrf - should get 419 error
  2. Submit with @csrf - should succeed
  3. Try replaying an old request - should fail
  4. Test AJAX requests include CSRF token
  5. Verify API routes use proper authentication

Best Practices

1. Use Sanctum for APIs

// routes/api.php
Route::middleware('auth:sanctum')->group(function () {
    Route::post('/user/update', [UserController::class, 'update']);
});

2. Handle CSRF Exceptions Gracefully

// app/Exceptions/Handler.php
use Symfony\Component\HttpKernel\Exception\HttpException;

public function render($request, Throwable $e)
{
    if ($e instanceof \Illuminate\Session\TokenMismatchException) {
        return redirect()
            ->back()
            ->withInput($request->except('password'))
            ->withErrors(['csrf' => 'Your session has expired. Please try again.']);
    }
    
    return parent::render($request, $e);
}

3. SPA Configuration

// routes/web.php
Route::get('/sanctum/csrf-cookie', function (Request $request) {
    return response()->noContent();
});
// Before making authenticated requests
await axios.get('/sanctum/csrf-cookie');
await axios.post('/api/endpoint', data);
  • Session Configuration
  • Brute Force Protection
  • API Rate Limiting

Automatically detect this issue

StackShield can automatically scan your Laravel application for this security issue and alert you when it's detected.

Start Free Trial
Was this guide helpful?