CSRF Protection
Protection against Cross-Site Request Forgery attacks
CSRF Protection in Laravel prevents Cross-Site Request Forgery attacks. This type of attack occurs when a malicious site tricks a user into sending unwanted requests to your site.
How it works:
Laravel creates a unique token for each session. This token must be sent in all POST/PUT/PATCH/DELETE forms. Laravel validates this token and rejects the request if it's not valid.
Features:
- Automatic token generation for each session
- Automatic validation in middleware
- Token rotation for more security
- Excluding specific routes (like webhooks)
- Support for AJAX requests
- Double Submit Cookie pattern
Usage:
- <code>@csrf</code> directive in Blade templates
- CSRF token in AJAX requests
- Excluding specific routes from CSRF protection
- Custom CSRF token handling
Examples
Usage in Blade
<form method="POST" action="/users">
@csrf
<input type="text" name="name">
<button type="submit">Submit</button>
</form>
<!-- Generates: -->
<!-- <input type="hidden" name="_token" value="..."> -->
@csrf directive creates a hidden input with CSRF token.
Usage in AJAX
<!-- In layout -->
<meta name="csrf-token" content="{{ csrf_token() }}">
<!-- In JavaScript -->
$.ajaxSetup({
headers: {
'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
}
});
// Or per request
$.ajax({
url: '/users',
method: 'POST',
headers: {
'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
},
data: { name: 'John' }
});
Setting CSRF token for all AJAX requests.
Exclude Routes from CSRF
<?php
namespace App\Http\Middleware;
use Illuminate\Foundation\Http\Middleware\VerifyCsrfToken as Middleware;
class VerifyCsrfToken extends Middleware
{
protected $except = [
'webhook/*',
'api/payment/callback',
'stripe/webhook',
];
}
Excluding specific routes from CSRF protection (like webhooks).
Custom CSRF Token Handling
<?php
namespace App\Http\Middleware;
use Illuminate\Foundation\Http\Middleware\VerifyCsrfToken as Middleware;
class VerifyCsrfToken extends Middleware
{
protected function tokensMatch($request)
{
// Custom token matching logic
$token = $request->input('_token') ?: $request->header('X-CSRF-TOKEN');
return hash_equals(
$request->session()->token(),
$token
);
}
protected function addCookieToResponse($request, $response)
{
// Custom cookie handling
$response->cookie('XSRF-TOKEN', csrf_token(), 60 * 24 * 7);
return $response;
}
}
Custom handling for CSRF token validation.
CSRF Token in API
<?php
// API routes typically don't use CSRF protection
// They use token-based authentication instead
// In routes/api.php
Route::middleware('auth:sanctum')->group(function () {
Route::post('/users', [UserController::class, 'store']);
// No CSRF token needed - uses Sanctum token
});
// But if you need CSRF for API
Route::middleware(['api', 'csrf'])->group(function () {
// CSRF protected API routes
});
CSRF protection in API routes which typically use token authentication.
CSRF Token Rotation
<?php
// Laravel automatically rotates CSRF token
// But you can customize it
// In VerifyCsrfToken middleware
protected function regenerateToken($request)
{
$request->session()->regenerateToken();
}
// Manual token regeneration
session()->regenerateToken();
// Get current token
$token = csrf_token();
Token rotation for more security.
CSRF in SPA
<!-- In SPA (Single Page Application) -->
<!-- Fetch token on app load -->
// In JavaScript
async function getCsrfToken() {
const response = await fetch('/csrf-token');
const data = await response.json();
return data.token;
}
// Use in requests
const token = await getCsrfToken();
fetch('/api/users', {
method: 'POST',
headers: {
'X-CSRF-TOKEN': token,
'Content-Type': 'application/json'
},
body: JSON.stringify({ name: 'John' })
});
// Or use cookie-based approach
// Laravel sets XSRF-TOKEN cookie automatically
Using CSRF token in Single Page Applications.
Testing CSRF Protection
<?php
namespace Tests\Feature;
use Tests\TestCase;
class CsrfTest extends TestCase
{
public function test_csrf_protection_blocks_request()
{
$response = $this->post('/users', [
'name' => 'John'
// No CSRF token
]);
$response->assertStatus(419);
}
public function test_csrf_protection_allows_valid_token()
{
$response = $this->post('/users', [
'name' => 'John',
'_token' => csrf_token()
]);
$response->assertStatus(200);
}
}
Testing CSRF protection in tests.
Use Cases
- Protecting form submissions from CSRF attacks
- Protecting state-changing operations
- Webhook endpoints that need to be excluded
- API endpoints using token authentication
- SPA applications requiring CSRF token
- AJAX requests that change state
Common Mistakes
- Forgetting @csrf in forms causing 419 error
- Excluding sensitive routes from CSRF causing security risk
- Not setting CSRF token for AJAX requests
- Using CSRF in API that uses token auth
- Forgetting token refresh in SPA
- Not handling 419 error in frontend
Best Practices
- Always use @csrf in forms
- Set CSRF token for AJAX requests
- Only exclude safe routes (like webhooks)
- Use token rotation for more security
- Handle 419 error in frontend
- Use cookie-based approach for SPA
- Test CSRF protection
Edge Cases
- CSRF token expiration in long-running forms
- Multiple tabs sharing token
- CSRF in iframe causing issues
- CSRF token in file uploads
- CSRF in API using session
- Token mismatch in load-balanced servers
Performance Notes
- CSRF validation overhead is very low
- Token generation and validation is fast
- Session-based tokens require session storage
- Cookie-based tokens are better for SPA
Security Notes
- CSRF protection is essential for state-changing operations
- Only exclude safe routes
- Use token rotation for more security
- Ensure token is stored in secure cookie
- Use SameSite cookie attribute
- Don't disable CSRF protection except in special cases
Interview Points
- What is CSRF attack and how does it work?
- How does Laravel implement CSRF protection?
- What is the difference between session-based and cookie-based CSRF token?
- When should you exclude route from CSRF?
- How can you use CSRF token in AJAX?
- What is token rotation and why is it important?
Version Notes
- Laravel 11.x: Improved performance in CSRF validation
- Laravel 11.x: Better support for cookie-based tokens
- Laravel 10.x: Improved token rotation mechanism
- Laravel 9.x: Improved SameSite cookie support