CSRF Protection
Cross-Site Request Forgery (CSRF) protection prevents attackers from executing unauthorized actions on behalf of authenticated users.
Protection Strategy
- Generate a unique token per session
- Include token in forms as hidden field
- Validate token on form submission
- Reject requests with missing or invalid tokens
Implementation
Token Generation
final class CsrfService
{
public function generateToken(): string
{
$token = bin2hex(random_bytes(32));
$this->session->set('csrf_token', $token);
return $token;
}
public function validateToken(string $token): bool
{
$storedToken = $this->session->get('csrf_token');
return $storedToken !== null && hash_equals($storedToken, $token);
}
}
Form Integration
<form method="post" action="/books/create">
<input type="hidden" name="_csrf_token" value="{{ csrf_token() }}">
<input type="text" name="title">
<button type="submit">Create</button>
</form>
Middleware Validation
if ($this->isWriteRequest($request)) {
$token = $this->extractToken($request);
if (!$this->csrfService->validateToken($token)) {
return $this->responseFactory->createResponse(403);
}
}
return $handler->handle($request);
SameSite Cookie Attribute
Modern browsers provide additional CSRF protection via the SameSite attribute:
- Strict: Cookie only sent for same-site requests
- Lax: Cookie sent for same-site requests and top-level navigation
Best Practices
- Always use CSRF tokens for state-changing operations
- Use
hash_equals()for constant-time comparison - Regenerate tokens after successful submission
- Don't expose tokens in URLs
See Also
- Session Management - CSRF tokens stored in session