Drupal adds tokens to forms for cross-site request forgery protection, but unconditionally skips doing so for anonymous users.

In most cases this does not matter (because if an anonymous user can submit a form, a potential attacker can just submit it themselves anyway), but in some cases where sites are displaying pages differently to different anonymous users (based on IP address or session information), it can matter, and it would be useful to have the option to add a form token in those cases.

This issue was discussed internally in the Drupal Security Team first, and we felt it could be a public issue due to its unusual nature and limited impact.

As for possible solutions, Heine, for example (who originally reported the issue related to this) suggested that if caching is disabled, that would be one case where we could easily add the token even if the form is being viewed by an anonymous user.

CommentFileSizeAuthor
#18 1803712.patch2.77 KBdrumm
#16 1803712.patch2.7 KBdrumm

Comments

greggles’s picture

An alternate solution would be to use the stateless csrf protection concept described here: http://appsandsecurity.blogspot.de/2012/01/stateless-csrf-protection.html

klausi’s picture

Issue summary: View changes

We might also consider a simpler approach with HTTP Origin or Referrer header checks as described on https://www.owasp.org/index.php/Cross-Site_Request_Forgery_%28CSRF%29_Pr... . That way we would have a stateless CSRF protection for anonymous users. Not sure about browser support for the Origin header.

klausi’s picture

The seckit module already does some Origin checks: http://cgit.drupalcode.org/seckit/tree/seckit.module#n327

So we could do something similar in the appropriate Form API places for anonymous users.

I'm still researching browser support. http://caniuse.com/cors seems to be only about CORS, which does not say anything about the Origin header alone.

klausi’s picture

I was experimenting a bit with Origin header checks today, but it seems that Firefox does not send it on POST requests https://stackoverflow.com/questions/29034776/why-does-firefox-not-always...

Version: 8.0.x-dev » 8.1.x-dev

Drupal 8.0.6 was released on April 6 and is the final bugfix release for the Drupal 8.0.x series. Drupal 8.0.x will not receive any further development aside from security fixes. Drupal 8.1.0-rc1 is now available and sites should prepare to update to 8.1.0.

Bug reports should be targeted against the 8.1.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.2.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

fgm’s picture

Referer information is increasingly not being sent either, so that's one less source of information (which was unreliable anyway).

alexpott’s picture

Version: 8.1.x-dev » 8.2.x-dev

Drupal 8.1.9 was released on September 7 and is the final bugfix release for the Drupal 8.1.x series. Drupal 8.1.x will not receive any further development aside from security fixes. Drupal 8.2.0-rc1 is now available and sites should prepare to upgrade to 8.2.0.

Bug reports should be targeted against the 8.2.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.3.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.2.x-dev » 8.3.x-dev

Drupal 8.2.6 was released on February 1, 2017 and is the final full bugfix release for the Drupal 8.2.x series. Drupal 8.2.x will not receive any further development aside from critical and security fixes. Sites should prepare to update to 8.3.0 on April 5, 2017. (Drupal 8.3.0-alpha1 is available for testing.)

Bug reports should be targeted against the 8.3.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.4.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.3.x-dev » 8.4.x-dev

Drupal 8.3.6 was released on August 2, 2017 and is the final full bugfix release for the Drupal 8.3.x series. Drupal 8.3.x will not receive any further development aside from critical and security fixes. Sites should prepare to update to 8.4.0 on October 4, 2017. (Drupal 8.4.0-alpha1 is available for testing.)

Bug reports should be targeted against the 8.4.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.5.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.4.x-dev » 8.5.x-dev

Drupal 8.4.4 was released on January 3, 2018 and is the final full bugfix release for the Drupal 8.4.x series. Drupal 8.4.x will not receive any further development aside from critical and security fixes. Sites should prepare to update to 8.5.0 on March 7, 2018. (Drupal 8.5.0-alpha1 is available for testing.)

Bug reports should be targeted against the 8.5.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.6.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.5.x-dev » 8.6.x-dev

Drupal 8.5.6 was released on August 1, 2018 and is the final bugfix release for the Drupal 8.5.x series. Drupal 8.5.x will not receive any further development aside from security fixes. Sites should prepare to update to 8.6.0 on September 5, 2018. (Drupal 8.6.0-rc1 is available for testing.)

Bug reports should be targeted against the 8.6.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.7.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

handkerchief’s picture

A security scan from one of our customers has reported this as a major security issue:

Cross-Site Request Forgery (in https://example.com/user/login)

Description :
In the majority of today's web applications, clients are required to submit forms
which can perform sensitive operations.
An example of such a form being used would be when an administrator wishes to
create a new user for the application.

In the simplest version of the form, the administrator would fill-in:
* Name
* Password
* Role (level of access)

Continuing with this example, Cross Site Request Forgery (CSRF) would occur when
the administrator is tricked into clicking on a link, which if logged into the
application, would automatically submit the form without any further interaction.
Cyber-criminals will look for sites where sensitive functions are performed in
this manner and then craft malicious requests that will be used against clients
via a social engineering attack.

There are 3 things that are required for a CSRF attack to occur:
1. The form must perform some sort of sensitive action.
2. The victim (the administrator the example above) must have an active session.
3. Most importantly, all parameter values must be **known** or **guessable**.

Arachni discovered that all parameters within the form were known or predictable
and therefore the form could be vulnerable to CSRF.

_Manual verification may be required to check whether the submission will then
perform a sensitive action, such as reset a password, modify user profiles, post
content on a forum, etc._

Solution :
Based on the risk (determined by manual verification) of whether the form submission
performs a sensitive action, the addition of anti-CSRF tokens may be required.
These tokens can be configured in such a way that each session generates a new
anti-CSRF token or such that each individual request requires a new token.
It is important that the server track and maintain the status of each token (in
order to reject requests accompanied by invalid ones) and therefore prevent
cyber-criminals from knowing, guessing or reusing them.
_For examples of framework specific remediation options, please refer to the references._

Same for:
https://example.com/user/password and others.

Question:
Is this really such a vulnerability? And how we can solve this?
We have already installed https://www.drupal.org/project/seckit but maybe with the wrong settings?

mcdruid’s picture

@handkerchief Drupal already uses anti-CSRF tokens in forms for authenticated users (such as the administrator in the report text that you quoted).

This issue is about adding CSRF protection for anonymous users, who would typically not have access to forms such as the one to create / modify other user accounts.

For details of the built-in CSRF protection, see for example:

https://www.drupal.org/docs/7/security/writing-secure-code/create-forms-...

For Drupal 8 you can see some of the code which handles CSRF tokens in, for example:

https://api.drupal.org/api/drupal/core%21lib%21Drupal%21Core%21Form%21Fo...

handkerchief’s picture

thx @mcdruid for your response. I'll do that.

drumm’s picture

Version: 8.6.x-dev » 8.8.x-dev
Status: Active » Needs review
Issue tags: +affects drupal.org
StatusFileSize
new2.7 KB

Some anonymous forms, like the login form, would benefit from CSRF hardening - https://cheatsheetseries.owasp.org/cheatsheets/Cross-Site_Request_Forger...

Attached is a D7 proof-of-concept. It could use some documentation and tests, if it is potentially a good approach.

anonymous_forms_with_token allows configuring specific forms to get an anonymous token. When one is generated, $_SESSION is used to stash when it was generated.

Since form tokens work as long as the form cache is there, these sessions are cleaned up once that expiration has passed, in drupal_session_commit(). This allows anonymous sessions to be deleted if they are used to make requests, without generating form tokens, for some time. They are also cleaned up on login by drupal_session_regenerate().

Status: Needs review » Needs work

The last submitted patch, 16: 1803712.patch, failed testing. View results

drumm’s picture

Status: Needs work » Needs review
StatusFileSize
new2.77 KB

Fixing the PHP notice.

Version: 8.8.x-dev » 8.9.x-dev

Drupal 8.8.0-alpha1 will be released the week of October 14th, 2019, which means new developments and disruptive changes should now be targeted against the 8.9.x-dev branch. (Any changes to 8.9.x will also be committed to 9.0.x in preparation for Drupal 9’s release, but some changes like significant feature additions will be deferred to 9.1.x.). For more information see the Drupal 8 and 9 minor version schedule and the Allowed changes during the Drupal 8 and 9 release cycles.

kmkelmor’s picture

My apologies if this is an incorrect way for using the comment feature. Since Detectify has declared the login-csrf vulnerability a medium level issue, I have to be able to fix this on my D7 site. Seckit didn't fix it, so I was trying this patch. Unfortunately it throws an undeclared _Session value in line 358 of session.inc
I'm at a loss as to what to try next. Any and all help is greatly appreciated. Thanks! kmkelmor

Version: 8.9.x-dev » 9.1.x-dev

Drupal 8.9.0-beta1 was released on March 20, 2020. 8.9.x is the final, long-term support (LTS) minor release of Drupal 8, which means new developments and disruptive changes should now be targeted against the 9.1.x-dev branch. For more information see the Drupal 8 and 9 minor version schedule and the Allowed changes during the Drupal 8 and 9 release cycles.

avpaderno’s picture

Status: Needs review » Needs work
Issue tags: +Needs reroll

The existing patches are for Drupal 7.x. I am not sure which is the correct status between Active and Needs work.

I would use the latter, since the existing patch needs to be re-rolled for Drupal 8.x. Please change the status if it's not correct.

Version: 9.1.x-dev » 9.2.x-dev

Drupal 9.1.0-alpha1 will be released the week of October 19, 2020, which means new developments and disruptive changes should now be targeted for the 9.2.x-dev branch. For more information see the Drupal 9 minor version schedule and the Allowed changes during the Drupal 9 release cycle.

Version: 9.2.x-dev » 9.3.x-dev

Drupal 9.2.0-alpha1 will be released the week of May 3, 2021, which means new developments and disruptive changes should now be targeted for the 9.3.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

Version: 9.3.x-dev » 9.4.x-dev

Drupal 9.3.0-rc1 was released on November 26, 2021, which means new developments and disruptive changes should now be targeted for the 9.4.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

Version: 9.4.x-dev » 9.5.x-dev

Drupal 9.4.0-alpha1 was released on May 6, 2022, which means new developments and disruptive changes should now be targeted for the 9.5.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

Version: 9.5.x-dev » 10.1.x-dev

Drupal 9.5.0-beta2 and Drupal 10.0.0-beta2 were released on September 29, 2022, which means new developments and disruptive changes should now be targeted for the 10.1.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

Version: 10.1.x-dev » 11.x-dev

Drupal core is moving towards using a “main” branch. As an interim step, a new 11.x branch has been opened, as Drupal.org infrastructure cannot currently fully support a branch named main. New developments and disruptive changes should now be targeted for the 11.x branch, which currently accepts only minor-version allowed changes. For more information, see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

mxr576’s picture

abarrio’s picture

According to #29 I made a test project and integrated the Symfony security-csrf library. It has worked perfect on anonymous and logged in users.

Maybe we can make the csrf token generation in Drupal to be made with this component.

Here is the example service that I used:

<?php

declare(strict_types=1);

namespace Drupal\test_token;

use Drupal\Core\Site\Settings;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\Security\Csrf\CsrfToken;
use Symfony\Component\Security\Csrf\CsrfTokenManager;
use Symfony\Component\Security\Csrf\CsrfTokenManagerInterface;
use Symfony\Component\Security\Csrf\TokenStorage\SessionTokenStorage;

/**
 * TokenManipulator responsible for handling CSRF token operations.
 */
class TokenManipulator {

  /**
   * Token intent to use on token manipulation.
   *
   * @var string
   */
  protected string $tokenIntent;

  public function __construct(
    Settings $settings,
    protected RequestStack $requestStack,
  ) {
    $this->tokenIntent = $settings->get('default_token_intent', '');
  }

  /**
   * {@inheritdoc}
   */
  public function isTokenValid(string $token): bool {
    $manager = $this->getManager();
    return $manager->isTokenValid(new CsrfToken($this->tokenIntent, $token));
  }

  /**
   * {@inheritdoc}
   */
  public function generateToken(): string {
    $manager = $this->getManager();
    $token = $manager->getToken($this->tokenIntent);
    return $token->getValue();
  }

  /**
   * Retrieves the CSRF token manager.
   *
   * If a session is available, the manager will use session-backed storage;
   * otherwise, it will default to in-memory storage for the request lifecycle.
   *
   * @return \Symfony\Component\Security\Csrf\CsrfTokenManagerInterface
   *   The CSRF token manager instance.
   */
  protected function getManager(): CsrfTokenManagerInterface {
    $request = $this->requestStack->getCurrentRequest();
    $session = $request?->getSession();

    // Use session-backed storage if a session is available; otherwise the
    // manager will keep tokens in-memory for the request lifecycle.
    $storage = $session ? new SessionTokenStorage($this->requestStack) : NULL;

    return new CsrfTokenManager(NULL, $storage);
  }

}

Version: 11.x-dev » main

Drupal core is now using the main branch as the primary development branch. New developments and disruptive changes should now be targeted to the main branch.

Read more in the announcement.