51 lines
1.2 KiB
PHP
51 lines
1.2 KiB
PHP
|
|
<?php
|
||
|
|
|
||
|
|
namespace App\Core\Middleware;
|
||
|
|
|
||
|
|
/**
|
||
|
|
* CSRF Middleware
|
||
|
|
* Cross-Site Request Forgery protection
|
||
|
|
*/
|
||
|
|
class CsrfMiddleware
|
||
|
|
{
|
||
|
|
public function handle(string $method, string $uri, callable $next): void
|
||
|
|
{
|
||
|
|
// Skip CSRF check for GET requests
|
||
|
|
if ($method === 'GET') {
|
||
|
|
$next();
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
// Skip CSRF check for API routes (if Accept header is application/json)
|
||
|
|
if (isset($_SERVER['HTTP_ACCEPT']) && str_contains($_SERVER['HTTP_ACCEPT'], 'application/json')) {
|
||
|
|
$next();
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
// Check CSRF token
|
||
|
|
$token = $_POST['_token'] ?? $_SERVER['HTTP_X_CSRF_TOKEN'] ?? null;
|
||
|
|
|
||
|
|
if (!$token || !$this->verifyToken($token)) {
|
||
|
|
http_response_code(419);
|
||
|
|
echo "<h1>419 - Page Expired</h1>";
|
||
|
|
echo "<p>CSRF token mismatch. Please refresh the page and try again.</p>";
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
// Continue to next middleware
|
||
|
|
$next();
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Verify CSRF token
|
||
|
|
*/
|
||
|
|
private function verifyToken(string $token): bool
|
||
|
|
{
|
||
|
|
if (!isset($_SESSION['csrf_token'])) {
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
return hash_equals($_SESSION['csrf_token'], $token);
|
||
|
|
}
|
||
|
|
}
|