attribute = $attribute; $this->ttl = $ttl; $this->tokenLength = $tokenLength; if (!is_callable($errorResponse)) { if (!$errorResponse instanceof ResponseInterface) { if (!is_string($errorResponse)) { $errorResponse = self::DEFAULT_ERROR_RESPONSE_STRING; } $errorResponse = new Response(400, ['content-type' => 'text/plain'], $errorResponse); } $errorResponse = function (ServerRequestInterface $request) use ($errorResponse) { return $errorResponse; }; } $this->errorResponse = $errorResponse; if (!$logger instanceof LoggerInterface) { $logger = new NullLogger(); } $this->logger = $logger; } public function setLogger(LoggerInterface $logger) { $this->logger = $logger; } public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface { if (!in_array(strtoupper($request->getMethod()), self::READ_METHODS)) { // This request is a write method and requires CSRF protection. if (!$this->isValid($request)) { return call_user_func($this->errorResponse, $request); } } // Otherwise, generate a new CSRF token, add it to the request attributes, and as a cookie on the response. $csrfToken = generateRandomString($this->tokenLength); $request = $request->withAttribute($this->attribute, $csrfToken); $response = $handler->handle($request); // Add the new CSRF cookie, restricting its scope to match the current request. $response = FigCookies\FigResponseCookies::set($response, FigCookies\SetCookie::create($this->attribute) ->withValue($csrfToken) ->withMaxAge($this->ttl) ->withSecure($request->getUri()->getScheme() == 'https') ->withDomain($request->getUri()->getHost()) ->withPath($request->getUri()->getPath())); return $response; } protected function isValid(ServerRequestInterface $request) { if (in_array($this->attribute, $request->getParsedBody())) { if (in_array($this->attribute, $request->getCookieParams())) { return hash_equals($request->getParsedBody()[$this->attribute], $request->getCookieParams()[$this->attribute]); } } return false; } }