Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
13 / 13
100.00% covered (success)
100.00%
2 / 2
CRAP
100.00% covered (success)
100.00%
1 / 1
CsrfAuditMiddleware
100.00% covered (success)
100.00%
13 / 13
100.00% covered (success)
100.00%
2 / 2
8
100.00% covered (success)
100.00%
1 / 1
 __construct
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 process
100.00% covered (success)
100.00%
12 / 12
100.00% covered (success)
100.00%
1 / 1
7
1<?php
2
3declare(strict_types=1);
4
5namespace App\Shared\Security;
6
7use App\Shared\Logging\CentralLogger;
8use Psr\Http\Message\ResponseInterface;
9use Psr\Http\Message\ServerRequestInterface;
10use Psr\Http\Server\MiddlewareInterface;
11use Psr\Http\Server\RequestHandlerInterface;
12use Yiisoft\Csrf\CsrfTokenInterface;
13
14 class CsrfAuditMiddleware implements MiddlewareInterface
15{
16    public function __construct(private  CsrfTokenInterface $csrfToken) {}
17
18    public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
19    {
20        $response = $handler->handle($request);
21
22        if (in_array($response->getStatusCode(), [422, 403], true) && in_array($request->getMethod(), ['POST', 'PUT', 'DELETE', 'PATCH'], true)) {
23            /** @var array<string, mixed> $parsedBody */
24            $parsedBody = (array) ($request->getParsedBody() ?? []);
25            $csrfInBody = isset($parsedBody['_csrf']) && is_string($parsedBody['_csrf']) ? $parsedBody['_csrf'] : 'NONE';
26            $providedToken = $request->getHeaderLine('X-CSRF-Token') ?: $csrfInBody;
27
28            CentralLogger::logSecurity('CSRF_TOKEN_MISMATCH', [
29                'from_url' => $request->getHeaderLine('Referer') ?: 'DIRECT/UNKNOWN',
30                'to_url' => (string) $request->getUri(),
31                'provided_token' => $providedToken,
32                'current_session_token' => $this->csrfToken->getValue(),
33            ]);
34        }
35
36        return $response;
37    }
38}