class CsrfRequestHeaderAccessCheck

Same name in other branches
  1. 9 core/lib/Drupal/Core/Access/CsrfRequestHeaderAccessCheck.php \Drupal\Core\Access\CsrfRequestHeaderAccessCheck
  2. 8.9.x core/lib/Drupal/Core/Access/CsrfRequestHeaderAccessCheck.php \Drupal\Core\Access\CsrfRequestHeaderAccessCheck
  3. 11.x core/lib/Drupal/Core/Access/CsrfRequestHeaderAccessCheck.php \Drupal\Core\Access\CsrfRequestHeaderAccessCheck

Access protection against CSRF attacks.

Hierarchy

Expanded class hierarchy of CsrfRequestHeaderAccessCheck

1 file declares its use of CsrfRequestHeaderAccessCheck
CsrfTokenController.php in core/modules/system/src/Controller/CsrfTokenController.php
1 string reference to 'CsrfRequestHeaderAccessCheck'
core.services.yml in core/core.services.yml
core/core.services.yml
1 service uses CsrfRequestHeaderAccessCheck
access_check.header.csrf in core/core.services.yml
Drupal\Core\Access\CsrfRequestHeaderAccessCheck

File

core/lib/Drupal/Core/Access/CsrfRequestHeaderAccessCheck.php, line 13

Namespace

Drupal\Core\Access
View source
class CsrfRequestHeaderAccessCheck implements AccessCheckInterface {
    
    /**
     * A string key that will used to designate the token used by this class.
     */
    const TOKEN_KEY = 'X-CSRF-Token request header';
    
    /**
     * The session configuration.
     *
     * @var \Drupal\Core\Session\SessionConfigurationInterface
     */
    protected $sessionConfiguration;
    
    /**
     * The token generator.
     *
     * @var \Drupal\Core\Access\CsrfTokenGenerator
     */
    protected $csrfToken;
    
    /**
     * Constructs a new rest CSRF access check.
     *
     * @param \Drupal\Core\Session\SessionConfigurationInterface $session_configuration
     *   The session configuration.
     * @param \Drupal\Core\Access\CsrfTokenGenerator $csrf_token
     *   The token generator.
     */
    public function __construct(SessionConfigurationInterface $session_configuration, CsrfTokenGenerator $csrf_token) {
        $this->sessionConfiguration = $session_configuration;
        $this->csrfToken = $csrf_token;
    }
    
    /**
     * {@inheritdoc}
     */
    public function applies(Route $route) {
        $requirements = $route->getRequirements();
        if (array_key_exists('_csrf_request_header_token', $requirements)) {
            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();
        // Read-only operations are always allowed.
        if (in_array($method, [
            'GET',
            'HEAD',
            'OPTIONS',
            'TRACE',
        ], TRUE)) {
            return AccessResult::allowed();
        }
        // This check only applies if
        // 1. the user was successfully authenticated and
        // 2. the request comes with a session cookie.
        if ($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);
    }

}

Members

Title Sort descending Modifiers Object type Summary Overriden Title
CsrfRequestHeaderAccessCheck::$csrfToken protected property The token generator.
CsrfRequestHeaderAccessCheck::$sessionConfiguration protected property The session configuration.
CsrfRequestHeaderAccessCheck::access public function Checks access.
CsrfRequestHeaderAccessCheck::applies public function Declares whether the access check applies to a specific route or not. Overrides AccessCheckInterface::applies
CsrfRequestHeaderAccessCheck::TOKEN_KEY constant A string key that will used to designate the token used by this class.
CsrfRequestHeaderAccessCheck::__construct public function Constructs a new rest CSRF access check.

Buggy or inaccurate documentation? Please file an issue. Need support? Need help programming? Connect with the Drupal community.