Problem/Motivation

Any route using the _csrf_token requirement doesn't work for users without session because the CSRF checker fails as the CSRF seed is not stored anywhere.

Proposed resolution

Only add a CSRF token if a session is started.

Remaining tasks

User interface changes

Flag supports anonymous users (and there was much rejoicing).

API changes

CsrfAccessCheck constructor requires a new argument but it's a service so noone should be constructing it anyways.

Data model changes

None.

CommentFileSizeAuthor
#147 drupal-11.2.3-2730351-147.patch16.13 KBjulienjoye
#143 drupal-10.4.2-2739351-143.patch23.45 KBlobodakyrylo
#141 drupal-10.4.2-2739351-141.patch23.48 KBsabrina.liman
#139 drupal-10.4.2-2739351-139.patch23.63 KBsabrina.liman
#135 drupal-core-10.3.7-2730351-135.patch23.67 KBalina.basarabeanu
#134 2730351-D10.3.x-134.patch23.92 KBgcalex5
#132 2730351-D10.3.x-132.patch24.49 KBlobodakyrylo
#128 2730351-D10.1.4-128.patch23.79 KBlobodakyrylo
#120 2730351-D9.5.9-120.patch23.75 KBsocialnicheguru
#118 2730351-nr-bot.txt145 bytesneeds-review-queue-bot
#117 2730351-117.patch24.23 KB_utsavsharma
#117 interdiff_116-117.txt1.88 KB_utsavsharma
#116 core-csrf-check-fails-for-users-without-session-2730351-116-9.5.0.patch24.25 KBb-prod
#114 2730351-114.patch24.23 KBanchal_gupta
#105 2730351-105.patch24.2 KBerick.major
#104 2730351-104.patch24.2 KBerick.major
#103 2730351-103.patch23.7 KBerick.major
#97 core-csrf-check-always-fails-for-users-without-session-2730351-96.patch15.09 KBlobodakyrylo
#95 core-csrf-check-always-fails-for-users-without-session-2730351-95.patch15.12 KBb-prod
#90 interdiff_87_90.txt2.74 KBanmolgoyal74
#90 2730351-90.patch14.22 KBanmolgoyal74
#89 interdiff-81-89.txt2.13 KBspadxiii
#89 2730351-89.patch15.27 KBspadxiii
#87 2730351-87.patch13.36 KBsuresh prabhu parkala
#86 2730351-82.patch15.29 KBlobodakyrylo
#81 2730351-81.patch15.28 KBneslee canil pinto
#68 csrf_check_always_fails-2730351-68_2.patch12.48 KBchrisroane
#57 interdiff-2730351-56-57.txt3.42 KByogeshmpawar
#57 csrf_check_always_fails-2730351-57.patch12.62 KByogeshmpawar
#56 csrf_check_always_fails-2730351-56.patch12.52 KBMunavijayalakshmi
#51 csrf_check_always_fails-2730351-51.patch13.01 KBcilefen
#34 interdiff.txt14.09 KBchx
#34 2730351_34.patch12.97 KBchx
#21 interdiff.txt4.19 KBchx
#21 2730351_21.patch11.99 KBchx
#18 2730351_18.patch11.76 KBchx
#18 interdiff.txt2.02 KBchx
#15 2730351_12.patch9.42 KBchx
#8 2730351_2.patch4.44 KBchx
#2 2730351_2.patch4.44 KBchx

Issue fork drupal-2730351

Command icon Show commands

Start within a Git clone of the project using the version control instructions.

Or, if you do not have SSH keys set up on git.drupalcode.org:

Comments

chx created an issue. See original summary.

chx’s picture

Title: CSRF checking anonymous users is pointless » CSRF checking links for anonymous users is pointless
StatusFileSize
new4.44 KB
damienmckenna’s picture

Version: 8.1.x-dev » 8.2.x-dev
Category: Bug report » Feature request

I'd think this would count as a feature request?

chx’s picture

Version: 8.2.x-dev » 8.1.x-dev
Category: Feature request » Bug report
Issue summary: View changes

Nope, it's a bug. Check the issue summary please. Also, the flag maintainers (not me) have filed #2475893: Support for Flagging by anonymous users as critical so postponing this issue to 8.2.x would mean postponing a flag stable until 8.2.0.

chx’s picture

However, the last thing I want is to fight in a core issue ever again. Either put this in 8.1.x or convince the flag maintainers to use for now the work around in the linked issue. Either is very fine by me. I do not particularly care, I am running a patched flag anyways.

damienmckenna’s picture

I'm not looking for a fight either :) I changed the issue to 8.2.x because I thought issues were supposed to be fixed in the newest active branch and then backported as appropriate? But I might have misunderstood how the 8 branches were working, so apologies if I was wrong in that.

And ok, I concur it's a bug.

chx’s picture

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

Ah. That's possible. I do not know the process either but I am guessing indeed it needs to be filed for 8.2.x although it applies with 8.1.x

chx’s picture

StatusFileSize
new4.44 KB

Reuploading the same patch for 8.2.x testing.

klausi’s picture

Title: CSRF checking links for anonymous users is pointless » CSRF checking links for requests without session cookie is pointless
Status: Needs review » Needs work
+++ b/core/lib/Drupal/Core/Access/CsrfAccessCheck.php
@@ -54,7 +61,7 @@ public function access(Route $route, Request $request, RouteMatchInterface $rout
+    if ($this->account->isAnonymous()  || $this->csrfToken->validate($request->query->get('token'), $path)) {

This should have a comment like "CSRF token checking is only useful for authenticated users because an attacker can always spoof an anonymous request themselves."

Hm, but now that I think of it: this is not depending on an authenticated user but on a session cookie. Instead of checking for an authenticated user we should check for an active session.

Then the comment should be "CSRF token checking is only useful for requests with an active cookie session because an attacker can always spoof an anonymous request themselves."

chx’s picture

I have thought of that but it is possible to authenticate yourself without a session, isn't it? What happens then? I even had a version which checked both for a session cookie and the anonymous user. I do not know, simply. In short, I would rather not deviate from the security team policy. Or are you talking in the name of the security team here?

klausi’s picture

I can only think of HTTP basic auth as other authentication system that is CSRF exploitable in a browser. OAuth requires additional HTTP headers or URL tokens. HTTP Basic auth is quite an edge case and not sure we should support that here. But ok, let's check for an authenticated user as you did.

My point is that the CSRF protection should also work for anonymous users that have an active session. Example: I have a commerce cart as anonymous user and there is a link to add items to my cart. Of course I don't want an attacker tricking me into adding more stuff to my cart. That should be CSRF protected.

So we could check for

if (($this->account->isAnonymous() && session_not_active()) || $this->csrfToken->validate($request->query->get('token'), $path)) {

Replace session_not_active() with whatever session service calls.

That would have the benefit of supporting active sessions with anonymous users, which is a use case for Drupal sites.

David_Rothstein’s picture

Title: CSRF checking links for requests without session cookie is pointless » CSRF checking on links is broken for anonymous users and should be removed

I don't think CSRF checking for anonymous users is necessarily pointless; with or without a session cookie there are situations where it makes sense (see #1803712: Allow form tokens to be used on anonymous forms in some cases).

But since the form API completely skips CSRF checking for anonymous users already (that's still true right?) it seems OK to me to do exactly the same thing for links, then repurpose the above issue to be about adding it (back) to both of them.

I can't think of any reason why links need to have more CSRF protection than forms do in the case of an anonymous user with a session. (Unless you're saying that since links already have more CSRF protection now, it's best to remove as little of that as possible in a stable release?)

Regarding a code comment, maybe just use something similar to what the form API does? http://cgit.drupalcode.org/drupal/tree/core/lib/Drupal/Core/Form/FormBui...

David_Rothstein’s picture

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

By the way, I think this is supposed to be filed against 8.1.x to be considered for 8.1.x (https://www.drupal.org/core/backport-policy). (Yes, it's backwards from how everything else works where you file/work on the issue for the newest version that it applies to, but I guess it has something to do with the cherry-picking...) I am not sure if it would make it into 8.1.x though.

klausi’s picture

OK, consistency with the form system makes sense.

So the patch only needs a comment, otherwise looks good to me.

chx’s picture

Status: Needs work » Needs review
StatusFileSize
new9.42 KB

Thank you David! Here's an entirely new patch also removing the CSRF token from the link. It still needs to bypass the checking for anonymous users because while the token is no longer there the access check will called, removing that call I believe is beyond this issue.

Status: Needs review » Needs work

The last submitted patch, 15: 2730351_12.patch, failed testing.

chx’s picture

It seems the tests added in #2512132: Make CSRF links cacheable relied on this, I pinged the authors of that issue asking for a fix of this test.

chx’s picture

Status: Needs work » Needs review
StatusFileSize
new2.02 KB
new11.76 KB

Here's a tentative fix. I am not sure whether the bubbling tests are meaningful still but I hope.

klausi’s picture

Status: Needs review » Needs work
  1. +++ b/core/lib/Drupal/Core/Access/CsrfAccessCheck.php
    @@ -54,7 +61,7 @@ public function access(Route $route, Request $request, RouteMatchInterface $rout
    +    if ($this->account->isAnonymous()  || $this->csrfToken->validate($request->query->get('token'), $path)) {
    

    2 spaces before "||". And the comment is missing why we check for the anonymous user.

  2. +++ b/core/lib/Drupal/Core/Access/RouteProcessorCsrf.php
    @@ -19,20 +20,26 @@ class RouteProcessorCsrf implements OutboundRouteProcessorInterface {
    +    if ($route->hasRequirement('_csrf_token') && $this->account->isAuthenticated()) {
    

    Should also have a comment why we bypass the check for anonymous users.

  3. +++ b/core/modules/system/src/Tests/Common/UrlTest.php
    @@ -43,6 +44,7 @@ function testLinkXSS() {
    +    \Drupal::currentUser()->setAccount(User::load(1));
    

    Should have a comment like "Set an authenticated user to make CSRF protected links work. @see RouteProcessorCSRF"

  4. +++ b/core/tests/Drupal/Tests/Core/Access/CsrfAccessCheckTest.php
    @@ -31,24 +31,34 @@ class CsrfAccessCheckTest extends UnitTestCase {
    +    $this->account = $this->getMock('Drupal\Core\Session\AccountInterface');
    

    Should use ::class syntax.

  5. +++ b/core/tests/Drupal/Tests/Core/Access/CsrfAccessCheckTest.php
    @@ -65,6 +75,24 @@ public function testAccessTokenPass() {
    +   * Tests the access() method for anonymous users.
    

    Should have @covers

+++ b/core/tests/Drupal/Tests/Core/Access/RouteProcessorCsrfTest.php
@@ -77,9 +87,30 @@ public function testProcessOutbound() {
+    $bubbleable_metadata = new BubbleableMetadata();
+    $this->processor->processOutbound('test', $route, $parameters, $bubbleable_metadata);
+    $this->assertEmpty($parameters);
+    $this->assertEquals((new BubbleableMetadata()), $bubbleable_metadata);

Hm, I think we should mock $bubbleable_metadata and assert that the addAttachments() method is never called.

dawehner’s picture

Th patch looks good, beside the points outlined by klausi.

The central question I have is: If we want to ignore CSRF for anonymous users, why do we still generate URLs with the token in there. When I understand \Drupal\Core\Access\CsrfTokenGenerator::get correctly, then we would simply generate a random token and then skip that in the access checker. I'm wondering whether we should / could suppress the generation of the token for anonymous users in \Drupal\Core\Access\RouteProcessorCsrf::renderPlaceholderCsrfToken

chx’s picture

Status: Needs work » Needs review
StatusFileSize
new11.99 KB
new4.19 KB

Regarding #19 4, 5, 6: I am just doing what's in the test right now. The test uses long interface syntax, no methods have covers and the the new testProcessOutboundForAnonymous is method copypasted wholesale from testProcessOutboundNoRequirement and testProcessOutbound. I have not written a single line of code in the new test method (aside from mocking an anonymous user of course). In the attached patch I have reverted from ::class to old style in RouteProcessorCsrfTest::setUp too because $this->csrfToken = $this->getMockBuilder('Drupal\Core\Access\CsrfTokenGenerator') just a few lines above. Perhaps a cleanup needs to happen but not in this issue IMO. There's enough confusion about how to write tests without mixing styles. It would be nice if someone lead an army of novices to convert every test from old style PHPunit mocking to prophecy... testOutboundPathAndRouteProcessing() had no mocks before so I was free to choose between phpunit and prophecy mocking so I have chosen prophecy and other modernities.

Regarding #20 the placeholder is added in RouteProcessorCsrf and the patch has a change to not add the token, so no need to change the renderPlaceholderCsrfToken.

Status: Needs review » Needs work

The last submitted patch, 21: 2730351_21.patch, failed testing.

chx’s picture

Status: Needs work » Needs review
pwolanin’s picture

Patch looks reasonable and seems to have a side effect of making those links more cacheable for anonymous users

chx’s picture

We really need badges on drupal.org: David Rothstein, klausi and pwolanin are security team members (David is also a core committer) so I begin to think this is not horribly insecure.

wim leers’s picture

wim leers’s picture

Issue tags: +Security

#20++: The central question I have is: If we want to ignore CSRF for anonymous users, why do we still generate URLs with the token in there.

But most importantly: #11++: My point is that the CSRF protection should also work for anonymous users that have an active session.


I think https://www.drupal.org/node/2319205 may be a bit misleading. It says:

Generating tokens for anonymous users would require running php code and generating sessions for anonymous users. Most Drupal sites use a page cache built into Drupal and many sites use an HTML cache (such as Varnish) which prevents the generation of a per-user token inside of forms.

It is true that most sites have page cache enabled (well, pretty much every D8 site, since it's enabled by default now). And so, yes, if your forms do not require a session to work, then it's meaningless to have a CSRF token in them. But there definitely still are forms for anonymous users where you want sessions (and hence also CSRF tokens): some forms are user/session-specific, some are not. Those that are not don't need a CSRF token. But in case of an anonymous user interacting with a form that is:

  1. a shopping cart, you want CSRF protection to prevent somebody adding products to my shopping cart on my behalf
  2. a flagging/voting thing, you want CSRF protection to prevent somebody voting on my behalf (and also to help reduce endless voting by the same user)

So I'm not quite convinced yet.

wim leers’s picture

We really need badges on drupal.org: David Rothstein, klausi and pwolanin are security team members (David is also a core committer) so I begin to think this is not horribly insecure.

That'd be very helpful indeed. Same for component maintainers.

catch’s picture

@Wim this issue is only about route/link CSRF protection, it won't affect forms at all.

wim leers’s picture

#29 But the same principles apply. Flagging/voting can be either via a link or via a form. You want CSRF protection either way.

chx’s picture

Yes, I was contemplating these scenarios myself but

  1. a shopping cart, you want CSRF protection to prevent somebody adding products to my shopping cart on my behalf -- well, what's "my" behalf if I am not authenticated? At one point I might add credit card information but there's no time between giving that and finalizing the shopping where another page could mess with my order. I do not think there's any site which remembers CC data for an anon user, that'd be insane.
  2. a flagging/voting thing, you want CSRF protection to prevent somebody voting on my behalf -- here I will presume you put an <img src="flagging link"> in your website to generate fraudulent votes and claim this gaming is harder to detect than just cURL'ing the flagging link over and over again because these will appear from different IPs and user agents. That's fair... except the referrer header will give you away.

Still, if we want we can add a session started check, that's easy. Do we want to?

wim leers’s picture

Still, if we want we can add a session started check, that's easy. Do we want to?

Yes, I think that then this makes sense. Basically the session.exists cache context's logic: \Drupal\Core\Cache\Context\SessionExistsCacheContext::getContext(). This is also what BigPipe uses, see \big_pipe_page_attachments().

catch’s picture

a shopping cart, you want CSRF protection to prevent somebody adding products to my shopping cart on my behalf -- well, what's "my" behalf if I am not authenticated? At one point I might add credit card information but there's no time between giving that and finalizing the shopping where another page could mess with my order. I do not think there's any site which remembers CC data for an anon user, that'd be insane.

There are certain things you could do like add a 'price-less' item to a cart that's part of a promotion to inflate numbers without the price changing.

Also some people might not notice an extra item or number of items in their cart before checking out - say if it's an order with a lot of items already. Thinking of online supermarket shopping where they almost put items in your cart themselves before they let you check out (three pages of "you're missing these promotions" " did you forget") or godaddy where you try to buy a domain and could end up with hosting, insurance, holiday in Crete etc. Given the upselling on sites like that, it'd be easy for an attacker to insert extra items without asking without someone reviewing their entire order again line by line.

So making session the distinction sounds good.

chx’s picture

StatusFileSize
new12.97 KB
new14.09 KB

The interdiff is larger than the patch itself... the patch is almost a ground up rewrite again -- only the places we patch are the same. It is slightly trickier than the account because sessionConfiguration::hasSession needs a request but the end result is better.

David_Rothstein’s picture

If session is the distinction, then shouldn't it be for forms too (which seems out of scope for this issue)?

I do think it's useful to have the same rules for CSRF protection on forms as on links, so that it's clear to people who have non-standard use cases (whether session-based or something else) whether Drupal is going to provide this security feature for them or whether it's their responsibility to handle the CSRF protection manually.

Hence the original suggestion to just bring links down to the level of forms here, and add more protection in a separate issue.

David_Rothstein’s picture

Eh that was a cross-post but maybe it proves the point since the patch is now a fair amount more complicated (and that's without even touching forms). The code looks good on a quick glance though.

chx’s picture

So what's next.

jibran’s picture

Status: Needs review » Reviewed & tested by the community
Issue tags: +Needs issue summary update, +Needs change record, +Needs change record updates

So making session the distinction sounds good.

+1 to this.

Hence the original suggestion to just bring links down to the level of forms here

I have run into those kind of scenarios in which we needed the token for anon user links so I don't think this is good idea.

If session is the distinction, then shouldn't it be for forms too (which seems out of scope for this issue)?

Let's discuss this in follow up.

Overall patch looks good. I think we need a better title, change notice, perhaps update existing change notices and updated issue summary here other then that it is RTBC.

chx’s picture

Title: CSRF checking on links is broken for anonymous users and should be removed » CSRF check always fails for users without a session
Issue summary: View changes
Issue tags: -Needs issue summary update, -Needs change record, -Needs change record updates
jibran’s picture

Thanks @chx for creating https://www.drupal.org/node/2759787.

Status: Reviewed & tested by the community » Needs work

The last submitted patch, 34: 2730351_34.patch, failed testing.

jibran’s picture

Status: Needs work » Reviewed & tested by the community

Fails seem unrelated so retested.

alexpott’s picture

So routes such as

outbound_processing_test.route.csrf:
  path: '/outbound_processing_test/route/csrf'
  requirements:
    _access: 'TRUE'
    _csrf_token: 'TRUE'

and

comment_test.report:
  path: '/comment/{comment}/report'
  defaults:
    _title: 'Report'
    _controller: '\Drupal\comment_test\Controller\CommentTestController::commentReport'
  requirements:
    _access: 'TRUE'
    _csrf_token: 'TRUE'

Yes these are test examples - but maybe contrib has real example... which before would not have worked for anon users now do? Maybe we should enforce that routes that use _crsf_token also have a _entity_access or _permission or maybe just don't have _access: 'TRUE'

This seems a risky behaviour change.

alexpott’s picture

Status: Reviewed & tested by the community » Needs review

Going to set back to needs review for more discussion of #43. I think the intention of the issue is correct - csrf protection should not apply to anons and that is consistent with forms BUT the behaviour change during a major release cycle seems risky.

chx’s picture

So then name it something else _csrf_token_new or something?

pwolanin’s picture

So, my understanding of prior Drupal versions was that CSRF tokens in forms were ignored by default for anonymous users. if you wanted them to be respected you had to do extra work yourself such as making sure the anonymous user had a session, that the form in question was not served from cache, and you adding back the validation.

This issue sounds like a bug fix to me - a bug fix may change incorrect behavior, so I am all in favor of fixing this.

The proposed fix sounds and looks reasonable, since it sounds like it would make it easier to support CSRF tokens for anonymous if desired.

I agree with David in #35 that the form and token behavior should be the same. I'm also not sure how readily this satisfies the need when a submission must have a CSRF token for anonymous - do you validate for the presence of a session or certain session data?

mlhess’s picture

mlhess’s picture

chx’s picture

How should I proceed to get this in.

xjm’s picture

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

I think we need to address #43 and #46.

Since there is some risk associated with this change (plus internal changes to add a service etc.), let's target it for the minor development version at least.

cilefen’s picture

StatusFileSize
new13.01 KB

Rerolling on 8.3.x. @socketwench got me interested in this issue.

khiminrm’s picture

Patch from #51 was successfully applied to Drupal 8.2.3 and fixed https://www.drupal.org/node/2835601. Thanks!

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

Drupal 8.3.0-alpha1 will be released the week of January 30, 2017, which means new developments and disruptive changes should now 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.

MaskOta’s picture

Issue tags: +Needs reroll

Patch no longer applies

Munavijayalakshmi’s picture

Assigned: Unassigned » Munavijayalakshmi
Status: Needs review » Needs work
Munavijayalakshmi’s picture

Version: 8.4.x-dev » 8.3.x-dev
Assigned: Munavijayalakshmi » Unassigned
Status: Needs work » Needs review
Issue tags: -Needs reroll
StatusFileSize
new12.52 KB

Rerolled the patch.

yogeshmpawar’s picture

Some more cleanup for previous patch & removed some coding standard issues also added a interdiff.

The last submitted patch, 56: csrf_check_always_fails-2730351-56.patch, failed testing.

Status: Needs review » Needs work

The last submitted patch, 57: csrf_check_always_fails-2730351-57.patch, failed testing.

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.

juliencarnot’s picture

Version: 8.4.x-dev » 8.5.x-dev
Issue tags: +Needs reroll

This issue is blocking the use of Dropzonejs for anonymous users in my project, which would be an important UX step (client-side resizing of images in a crowdsourced/mobile context). I can't do much but I'm willing to test a patch that applies on 8.4 if somebody can reroll it.

jofitz’s picture

Issue tags: -Needs reroll

This patch applies cleanly to 8.4.x (and 8.5.x) so does not need a re-roll.

juliencarnot’s picture

Status: Needs work » Needs review

Sorry about that, I assumed the lasts tests failed for that reason.

wim leers’s picture

Status: Needs review » Needs work

This does need work though, because it's not yet passing tests.

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

Drupal 8.5.0-alpha1 will be released the week of January 17, 2018, which means new developments and disruptive changes should now 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.6.x-dev » 8.7.x-dev

Drupal 8.6.0-alpha1 will be released the week of July 16, 2018, which means new developments and disruptive changes should now 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.

Uncle_Drewbie’s picture

#57 does not cleanly apply to 8.5.6

chrisroane’s picture

Status: Needs work » Needs review
StatusFileSize
new12.48 KB

I re-rolled the patch from #57 based on the 8.6.x branch. This gets applied properly in 8.5.6.

The only change that I couldn't implement was in "core/modules/system/src/Tests/Common/UrlTest.php", since that file doesn't exist in 8.6.x. I'm not 100% sure on everything all of this code does, but I was careful in applying each code change and making sure there wasn't any php errors. Hopefully tests pass from this patch.

I verified that I am able to upload files via dropzonejs as an anonymous user. So this fixes the main issue for our use case.

Status: Needs review » Needs work

The last submitted patch, 68: csrf_check_always_fails-2730351-68_2.patch, failed testing. View results
- codesniffer_fixes.patch Interdiff of automated coding standards fixes only.

chrisroane’s picture

ugh, it looks like tests are failing. :( Not sure how to fix. But the patch works.

orkut murat yılmaz’s picture

The patch from #57 is trying to find /core/modules/system/src/Tests/Common/UrlTest.php, on last step, but the file doesn't exist for neither 8.5.6 nor 8.5.8.

Line number is 140 for patch from #57.

lykyd’s picture

I've applied the patch #68 on 8.5.8. It went through but did not fix the issue.

mbovan’s picture

I have applied #68 in my project.

Custom route configuration:

example.node.custom:
  path: '/node/{node}/example'
  defaults:
    _controller: '\Drupal\example\Controller\ExampleController::example'
    _title: 'Example'
  requirements:
    _entity_access: 'node.view'
    node: \d+
  options:
    parameters:
      node:
        type: entity:node

Tested with the following scenarios:

  1. Clear the cookies
  2. Log in as an authenticated user
  3. Go to the sample page that contains a CSRF link generated from example.node.custom route
  4. Click the link -> access allowed

  5. Log out
  6. Go to the sample page that contains the CSRF link generated from example.node.custom route
  7. Click the link -> access denied. This happens as \Drupal\Core\Access\CsrfAccessCheck::access() thinks the request still has the session

However, the scenario

  1. Clear the cookies
  2. Open the site as an anonymous user
  3. Go to the sample page that contains the CSRF link generated from example.node.custom route
  4. Click the link -> access allowed

works fine.

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

Drupal 8.7.0-alpha1 will be released the week of March 11, 2019, which means new developments and disruptive changes should now be targeted against the 8.8.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

Question:

We have this problem:
https://www.drupal.org/project/drupal/issues/1803712#comment-13082004

Can you also provide these forms with a token if the issue on this page is solved?

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.

Marko B’s picture

I used this patch here on vote up_down module as it didnt work for both anon/auth users. Patch helps with anon but auth. users still cant use the widget for voting. Cross referencing it

https://www.drupal.org/project/vote_up_down/issues/3113901#comment-13467274

capysara’s picture

Patch applies to 8.8.4. It throws an error the first time I clear the caches, but no errors on the second cache clear. Patch allows anonymous users use the DropzoneJS uploader.

orkut murat yılmaz’s picture

@capysara, what does the first error message include?

capysara’s picture

PHP Fatal error: Uncaught ArgumentCountError: Too few arguments to function Drupal\Core\Access\RouteProcessorCsrf::__construct(), 1 passed in /var/www/drupalvm/drupal/docroot/core/lib/Drupal/Component/DependencyInjection/Container.php on line 269 and exactly 3 expected in /var/www/drupalvm/drupal/docroot/core/lib/Drupal/Core/Access/RouteProcessorCsrf.php:49
Stack trace:
#0 /var/www/drupalvm/drupal/docroot/core/lib/Drupal/Component/DependencyInjection/Container.php(269): Drupal\Core\Access\RouteProcessorCsrf->__construct(Object(Drupal\Core\Access\CsrfTokenGenerator))
#1 /var/www/drupalvm/drupal/docroot/core/lib/Drupal/Component/DependencyInjection/Container.php(173): Drupal\Component\DependencyInjection\Container->createService(Array, 'route_processor...')
#2 /var/www/drupalvm/drupal/docroot/core/lib/Drupal/Component/DependencyInjection/Container.php(487): Drupal\Component\DependencyInjection\Container->get('route_processor...', 1)
#3 /var/www/drupalvm/drupal/docroot/core/lib/Drupal/Component/DependencyInjection/Container.php( in /var/www/drupalvm/drupal/docroot/core/lib/Drupal/Core/Access/RouteProcessorCsrf.php on line 49

Fatal error: Uncaught ArgumentCountError: Too few arguments to function Drupal\Core\Access\RouteProcessorCsrf::__construct(), 1 passed in /var/www/drupalvm/drupal/docroot/core/lib/Drupal/Component/DependencyInjection/Container.php on line 269 and exactly 3 expected in /var/www/drupalvm/drupal/docroot/core/lib/Drupal/Core/Access/RouteProcessorCsrf.php:49
Stack trace:
#0 /var/www/drupalvm/drupal/docroot/core/lib/Drupal/Component/DependencyInjection/Container.php(269): Drupal\Core\Access\RouteProcessorCsrf->__construct(Object(Drupal\Core\Access\CsrfTokenGenerator))
#1 /var/www/drupalvm/drupal/docroot/core/lib/Drupal/Component/DependencyInjection/Container.php(173): Drupal\Component\DependencyInjection\Container->createService(Array, 'route_processor...')
#2 /var/www/drupalvm/drupal/docroot/core/lib/Drupal/Component/DependencyInjection/Container.php(487): Drupal\Component\DependencyInjection\Container->get('route_processor...', 1)
#3 /var/www/drupalvm/drupal/docroot/core/lib/Drupal/Component/DependencyInjection/Container.php( in /var/www/drupalvm/drupal/docroot/core/lib/Drupal/Core/Access/RouteProcessorCsrf.php on line 49
[error] Drush command terminated abnormally due to an unrecoverable error.
Error: Uncaught ArgumentCountError: Too few arguments to function Drupal\Core\Access\RouteProcessorCsrf::__construct(), 1 passed in /var/www/drupalvm/drupal/docroot/core/lib/Drupal/Component/DependencyInjection/Container.php on line 269 and exactly 3 expected in /var/www/drupalvm/drupal/docroot/core/lib/Drupal/Core/Access/RouteProcessorCsrf.php:49
Stack trace:
#0 /var/www/drupalvm/drupal/docroot/core/lib/Drupal/Component/DependencyInjection/Container.php(269): Drupal\Core\Access\RouteProcessorCsrf->__construct(Object(Drupal\Core\Access\CsrfTokenGenerator))
#1 /var/www/drupalvm/drupal/docroot/core/lib/Drupal/Component/DependencyInjection/Container.php(173): Drupal\Component\DependencyInjection\Container->createService(Array, 'route_processor...')
#2 /var/www/drupalvm/drupal/docroot/core/lib/Drupal/Component/DependencyInjection/Container.php(487): Drupal\Component\DependencyInjection\Container->get('route_processor...', 1)
#3 /var/www/drupalvm/drupal/docroot/core/lib/Drupal/Component/DependencyInjection/Container.php( in /var/www/drupalvm/drupal/docroot/core/lib/Drupal/Core/Access/RouteProcessorCsrf.php, line 49

neslee canil pinto’s picture

Status: Needs work » Needs review
StatusFileSize
new15.28 KB

Status: Needs review » Needs work

The last submitted patch, 81: 2730351-81.patch, failed testing. View results
- codesniffer_fixes.patch Interdiff of automated coding standards fixes only.

neslee canil pinto’s picture

Status: Needs work » Needs review

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.

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.

lobodakyrylo’s picture

StatusFileSize
new15.29 KB
suresh prabhu parkala’s picture

StatusFileSize
new13.36 KB

Patch did not apply. Here is a re-rolled patch. Please review.

Status: Needs review » Needs work

The last submitted patch, 87: 2730351-87.patch, failed testing. View results
- codesniffer_fixes.patch Interdiff of automated coding standards fixes only.

spadxiii’s picture

StatusFileSize
new15.27 KB
new2.13 KB

A quick reroll of 81 for drupal 8.9

ps. this patch breaks some more tests than are fixed in the patch

anmolgoyal74’s picture

StatusFileSize
new14.22 KB
new2.74 KB

Tried to fix failed tests in #87

anmolgoyal74’s picture

Status: Needs work » Needs review

Status: Needs review » Needs work

The last submitted patch, 90: 2730351-90.patch, failed testing. View results

mxr576’s picture

Patch #90 fails with a serious regression, forbidden responses became allowed. This definitely needs work.

/**
* Constructs a CsrfAccessCheck object.
*
* @param \Drupal\Core\Access\CsrfTokenGenerator $csrf_token
* The CSRF token generator.
+ * @param \Drupal\Core\Session\SessionConfigurationInterface $session_configuration
+ * The session configuration.
*/
- public function __construct(CsrfTokenGenerator $csrf_token) {
+ public function __construct(CsrfTokenGenerator $csrf_token, SessionConfigurationInterface $session_configuration) {
$this->csrfToken = $csrf_token;

Should the new SessionConfigurationInterface dependency be nullable everywhere if we would like to introduce this fix in 9.x?

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.

b-prod’s picture

Status: Needs work » Needs review
StatusFileSize
new15.12 KB

@amxr576 you're right, as the access result differ from entity and non-entity.

This patch applies to the latest version of 9.2.x and tries to handle such case, as returning "neutral" result for route using entity_access leads to security flaw.

Status: Needs review » Needs work
lobodakyrylo’s picture

I changed patch for 9.3.x version.

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.

bradjones1’s picture

  1. +++ b/core/lib/Drupal/Core/Access/CsrfAccessCheck.php
    @@ -54,7 +65,27 @@ public function access(Route $route, Request $request, RouteMatchInterface $rout
    +    if (!$this->sessionConfiguration || !$this->sessionConfiguration->hasSession($request)) {
    

    It seems this would mean that if the sessionConfiguration property is not set (e.g., you extended the class but did not update to include the new argument to the constructor) this code block applies even for authenticated users. Which does not appear to be the intent.

  2. +++ b/core/lib/Drupal/Core/Access/CsrfAccessCheck.php
    @@ -23,14 +24,24 @@ class CsrfAccessCheck implements RoutingAccessInterface {
    +  public function __construct(CsrfTokenGenerator $csrf_token, ?SessionConfigurationInterface $session_configuration = NULL) {
         $this->csrfToken = $csrf_token;
    +    $this->sessionConfiguration = $session_configuration;
    

    Per above I think this needs to be retrieved from the \Drupal global DI container if it's not provided, and throw a deprecation notice.

  3. +++ b/core/lib/Drupal/Core/Access/CsrfAccessCheck.php
    @@ -54,7 +65,27 @@ public function access(Route $route, Request $request, RouteMatchInterface $rout
    +      // We cannot return a neutral result, as this will mean "forbidden". This
    +      // may lead to unexpected behavior, when dealing with entity access, as
    +      // an "allowed" response will take over any "forbidden" one...
    +      // @see https://www.drupal.org/project/drupal/issues/2991698
    +      // @see https://www.drupal.org/project/drupal/issues/2861074
    +      if ($route->getRequirement('_entity_access') !== NULL) {
    +        $result = AccessResult::neutral('Anonymous users do not need CSRF checking');
    

    This is confusing to read, it says we can't return a neutral result, but then we do. I read through the linked issues and particularly https://www.drupal.org/project/drupal/issues/2991698#comment-14009628 explains this Drupal WTF, but it's still unclear here.

  4. +++ b/core/lib/Drupal/Core/Access/CsrfAccessCheck.php
    @@ -54,7 +65,27 @@ public function access(Route $route, Request $request, RouteMatchInterface $rout
    +      // Regarding non-entity route access, this is not an issue as any "neutral"
    +      // or "forbidden" result with take precedence.
    

    This needs grammar cleanup.

bradjones1’s picture

Note to self, the patch that seems to be most recently seen by core maintainers is #51. The patch reviewed above includes changes in #95 relating to entity routes; I've read through the comments and I'm not entirely clear why that needs to be in here at all, actually.

@xjm last chimed in on this at #50. I came here from #3055260: [PP-1] Disable CSRF token check for non-CSRF vulnerable authentication providers which is a similar problem space (need to disable CSRF checks) but is a little (a lot?) simpler b/c it only hinges on the authentication method used, so by definition only speaks to authenticated users. That will be easier than here, where there's question around when and how to apply CSRF protection for anons, and URL generation.

kazah’s picture

Any update for d9.3 ?

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.

erick.major’s picture

StatusFileSize
new23.7 KB

I've updated patch #51 to the code standard required by both version d9.3 and above.

erick.major’s picture

StatusFileSize
new24.2 KB

Fixing test issues.

erick.major’s picture

StatusFileSize
new24.2 KB

Fixing PHPCS issues.

erick.major’s picture

Status: Needs work » Needs review
erick.major’s picture

alina.basarabeanu’s picture

Patch #105 works on drupal/core (9.4.2)

smustgrave’s picture

Rerunning the tests for 9.5.x

Any testing steps would be great!

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.

jamesyao’s picture

I have a related issue about dropzonejs/upload 403 error for the anonymous users in Drupal core 9.4.7 after the site was upgraded from Core 9.3.6 to 9.4.7.

It worked well for the anonymous users to upload Media files in Drupal Core 9.3.6. Now the "en/dropzonejs/upload?token=WcMvqfFb5tLuF1kfaxBZhTspoW9enzzs4bf02xp9gc0. Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException: 'csrf_token' URL query argument is invalid" error occurs. I applied the patch (2730351-105.patch) in the site. As a result, the error is gone. But the anonymous user still can't upload the files in the Core 9.4.7.

jamesyao’s picture

Great work. Thank you @erick.major for providing the patch #105!

The patch allows the anonymous user to upload the files on Drupal Core 9.4.7. For some reason, the file is not converted as a Media type and its status indicates "Temporary" even though the Administer media permission is granted to anonymous user role.

jamesyao’s picture

Hi @erick.major, do you have any suggestions on why the media item is not generated after the file was uploaded by the anonymous user in Drupal Core 9.4.7. And the uploaded file status shows "Temporary" in file_managed table and the file list (/en/admin/content/files). The anonymous user role has the Administer media permission. Thank you.

anchal_gupta’s picture

StatusFileSize
new24.23 KB

Rerolled the patch against 10.1x.

joseph.olstad’s picture

b-prod’s picture

Re-roll against core 9.5.0

_utsavsharma’s picture

StatusFileSize
new1.88 KB
new24.23 KB

Fixed CCF for #116.
Please review.

needs-review-queue-bot’s picture

Status: Needs review » Needs work
StatusFileSize
new145 bytes

The Needs Review Queue Bot tested this issue. It either no longer applies to Drupal core, or fails the Drupal core commit checks. Therefore, this issue status is now "Needs work".

Apart from a re-roll or rebase, this issue may need more work to address feedback in the issue or MR comments. To progress an issue, incorporate this feedback as part of the process of updating the issue. This helps other contributors to know what is outstanding.

Consult the Drupal Contributor Guide to find step-by-step guides for working with issues.

socialnicheguru’s picture

No longer applies to Drupal 9.5.9.

socialnicheguru’s picture

StatusFileSize
new23.75 KB

I rerolled the patch for Drupal 9.5.9
I have to learn to how to do a proper interdiff.
The changes below are just text changes in comments

patching file 'core/core.services.yml'
patching file 'core/lib/Drupal/Core/Access/CsrfAccessCheck.php'
patching file 'core/lib/Drupal/Core/Access/RouteProcessorCsrf.php'
patching file 'core/modules/menu_link_content/tests/src/Kernel/MenuLinkContentCacheabilityBubblingTest.php'
1 out of 4 hunks failed--saving rejects to 'core/modules/menu_link_content/tests/src/Kernel/MenuLinkContentCacheabilityBubblingTest.php.rej'
patching file 'core/modules/system/tests/src/Kernel/Common/UrlTest.php'
1 out of 7 hunks failed--saving rejects to 'core/modules/system/tests/src/Kernel/Common/UrlTest.php.rej'
patching file 'core/tests/Drupal/Tests/Core/Access/CsrfAccessCheckTest.php'
patching file 'core/tests/Drupal/Tests/Core/Access/RouteProcessorCsrfTest.php'

more core/modules/menu_link_content/tests/src/Kernel/MenuLinkContentCacheabilityBubblingTest.php.rej
@@ -15,6 +15,8 @@
use Symfony\Component\Routing\Route;

/**
+ * The menu link content cache bubbling kernel tests.
+ *
* Ensures that rendered menu links bubble the necessary bubbleable metadata
* for outbound path/route processing.
*

more core/modules/system/tests/src/Kernel/Common/UrlTest.php.rej
@@ -12,6 +12,8 @@
use Drupal\KernelTests\KernelTestBase;

/**
+ * Url kernel tests.
+ *
* Confirm that \Drupal\Core\Url,
* \Drupal\Component\Utility\UrlHelper::filterQueryParameters(),
* \Drupal\Component\Utility\UrlHelper::buildQuery(), and

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.

rpayanm made their first commit to this issue’s fork.

rpayanm’s picture

Status: Needs work » Needs review

Please review.

bradjones1’s picture

Status: Needs review » Needs work

Test failure.

rpayanm’s picture

Status: Needs work » Needs review

Sorry, I can see the all tests passed. Which tests failed?

smustgrave’s picture

Status: Needs review » Needs work

Left some feedback on the MR.

lobodakyrylo’s picture

StatusFileSize
new23.79 KB

Rerolled patch for D10.1.x

joum’s picture

Can confirm #128 applies cleanly and works on Drupal 10.1.6

bradjones1’s picture

This needs an MR against 11.x at this point.

joseph.olstad’s picture

It's possible to remove/disable the CSRF check by using a directive set to the modulename.routing.yml file

see how this patch for dropzonejs is doing it:
#3197207-02: Anonymous users cannot upload caused by invalid csrf-token

lobodakyrylo’s picture

StatusFileSize
new24.49 KB

This patch is for 10.3.x version

socialnicheguru’s picture

gcalex5’s picture

StatusFileSize
new23.92 KB

#132 failed to apply for me on 10.3.0. Re-rolled against branch 10.3.x

alina.basarabeanu’s picture

StatusFileSize
new23.67 KB

A new patch for Drupal Core 10.3.7 was generated from 2730351-D10.3.x-134 patch

lobodakyrylo’s picture

The patch #135 stopped working after updating to 10.4.2

bhanu951 made their first commit to this issue’s fork.

agoradesign’s picture

confirm #136 - patch #135 works until 10.4.1, stopped working with 10.4.2

couldn't apply the MR diff either, so I'm stuck at 10.4.1 for the given project :(

sabrina.liman’s picture

Version: 11.x-dev » 10.4.x-dev
Category: Bug report » Task
StatusFileSize
new23.63 KB

A new patch for Drupal Core 10.4.2 was generated from drupal-core-10.3.7-2730351-135.patch

ptmkenny’s picture

Version: 10.4.x-dev » 11.x-dev
Category: Task » Bug report

@sabrina.liman Please do not change the version or the category. Core development is currently on 11.x.

sabrina.liman’s picture

StatusFileSize
new23.48 KB

Error occurred with #139

PHP Deprecated: Optional parameter $requestStack declared before required parameter $session_configuration is implicitly treated as a required parameter in /var/www/html/docroot/core/lib/Drupal/Core/Access/RouteProcessorCsrf.php on line 28

Deprecated: Optional parameter $requestStack declared before required parameter $session_configuration is implicitly treated as a required parameter in /var/www/html/docroot/core/lib/Drupal/Core/Access/RouteProcessorCsrf.php on line 28
PHP Fatal error: Uncaught TypeError: Drupal\Core\Access\RouteProcessorCsrf::__construct(): Argument #2 ($requestStack) must be of type ?Symf
ony\Component\HttpFoundation\RequestStack, Drupal\Core\Session\SessionConfiguration given, called in /var/www/html/docroot/core/lib/Drupal/Co
mponent/DependencyInjection/Container.php on line 261 and defined in /var/www/html/docroot/core/lib/Drupal/Core/Access/RouteProcessorCsrf.php:28

bhanu951’s picture

@sabrina.liman , patches are no longer preferred, please use existing MR to contribute or create a different MR if you have an alternative solution than the existing one.

lobodakyrylo’s picture

StatusFileSize
new23.45 KB

Patch #141 also doesn't work since it has a critical issue: Uncaught PHP Exception Error: "Call to a member function hasSession() on null" at /core/lib/Drupal/Core/Access/RouteProcessorCsrf.php line 44

I understand MR is better, but I didn't have enough time to do that.

harlor made their first commit to this issue’s fork.

julienjoye made their first commit to this issue’s fork.

julienjoye’s picture

StatusFileSize
new16.13 KB

In the meantime, if you still need this patch to be applied on a drupal 11.2.3 instance, here is a bump.

mxr576 changed the visibility of the branch 2730351-csrf-for-anonymous to hidden.

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.