sessionConfiguration = $session_configuration; $this->csrfToken = $csrf_token; } /** * {@inheritdoc} */ public function applies(Route $route) { $requirements = $route->getRequirements(); // Check for current requirement _csrf_request_header_token and deprecated // REST requirement. $applicable_requirements = [ '_csrf_request_header_token', // @todo Remove _access_rest_csrf in Drupal 9.0.0. '_access_rest_csrf', ]; $requirement_keys = array_keys($requirements); if (array_intersect($applicable_requirements, $requirement_keys)) { if (isset($requirements['_method'])) { // There could be more than one method requirement separated with '|'. $methods = explode('|', $requirements['_method']); // CSRF protection only applies to write operations, so we can filter // out any routes that require reading methods only. $write_methods = array_diff($methods, ['GET', 'HEAD', 'OPTIONS', 'TRACE']); if (empty($write_methods)) { return FALSE; } } // No method requirement given, so we run this access check to be on the // safe side. return TRUE; } } /** * Checks access. * * @param \Symfony\Component\HttpFoundation\Request $request * The request object. * @param \Drupal\Core\Session\AccountInterface $account * The currently logged in account. * * @return \Drupal\Core\Access\AccessResultInterface * The access result. */ public function access(Request $request, AccountInterface $account) { $method = $request->getMethod(); // This check only applies if // 1. this is a write operation // 2. the user was successfully authenticated and // 3. the request comes with a session cookie. if (!in_array($method, ['GET', 'HEAD', 'OPTIONS', 'TRACE']) && $account->isAuthenticated() && $this->sessionConfiguration->hasSession($request) ) { if (!$request->headers->has('X-CSRF-Token')) { return AccessResult::forbidden()->setReason('X-CSRF-Token request header is missing')->setCacheMaxAge(0); } $csrf_token = $request->headers->get('X-CSRF-Token'); // @todo Remove validate call using 'rest' in 8.3. // Kept here for sessions active during update. if (!$this->csrfToken->validate($csrf_token, self::TOKEN_KEY) && !$this->csrfToken->validate($csrf_token, 'rest')) { return AccessResult::forbidden()->setReason('X-CSRF-Token request header is invalid')->setCacheMaxAge(0); } } // Let other access checkers decide if the request is legit. return AccessResult::allowed()->setCacheMaxAge(0); } }