Problem/Motivation

When requesting an image through an image style URL (e.g. .../files/styles/my-style/public/my-image.jpg), but the original image file (.../files/my-image.jpg) does not exist, it would make more sense for Drupal to return a Page Not Found (404), instead of an Access Denied error (403).

Reasons:

1. When requesting .../files/my-image.jpg (i.e. without the image style portion), Drupal returns a 404.
2. In certain server configurations, 404's are cached for some time, but 403's aren't. In this case, a DDoS attack could be made to the server by simply requesting many images that don't exist.

Proposed resolution

Quoting @catch in #32

There are several scenarios. The first value in parenthesis is the current behaviour, the second is what the patch changes it to (if there's a change).

1. Valid itok + derivative on disk (200)
2. Invalid/no itok + derivative on disk + source image (200)
3. Invalid/no itok + derivative on disk + no source image (200)
4. Valid itok + source image (200)
5. Valid itok + no source image (404)
6. Invalid itok + source image (403) (404) - we check the itok before checking file_exists() and return early
7. Invalid itok + no source image (403) (404)

Remaining tasks

Review / improve existing patches.

User interface changes

Drupal will now return a 404 (Page Not Found) instead of a 403 (Access Denied) when an itok is invalid or an itok is invalid and the source image doesn't exist.

API changes

None.

Data model changes

None.

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

cambraca’s picture

Status: Active » Needs review

Status: Needs review » Needs work

The last submitted patch, drupal-image-style-not-found.patch, failed testing.

The last submitted patch, drupal-image-style-not-found.patch, failed testing.

cambraca’s picture

Status: Needs work » Needs review
FileSize
3.43 KB

Of course I forgot to update the .test file. Here is an updated patch.

cashwilliams’s picture

Assigned: cambraca » Unassigned
Status: Needs review » Reviewed & tested by the community

This was causing major performance issues for a very large site we launched. An external app vender had stripped the query parameters from image requests, thus causing a huge amount of 403s. These were all hitting origin and made up for 70% of the origin traffic.

I reviewed the thread which introduced this feature from the security patch, and from what I can tell a 403 was chosen because a menu access was refactored from returning false. My guess is since the original solution using menu access would return a 403, the same value was kept in the refactoring.

Does anyone have any reasons this should not be a 404?

Status: Reviewed & tested by the community » Needs work

The last submitted patch, 4: drupal-image-style-not-found-2211429-4.patch, failed testing.

cambraca’s picture

The test did not complete due to a fatal error.
Completion check
theme.test
471
ThemeRegistryTestCase->testRaceCondition()

Why would this test fail now if it passed before?

Status: Needs work » Needs review
David_Rothstein’s picture

I would guess the rationale for a 403 is that your request to the server is trying to do something (generate an image) but the system is choosing not to allow you to do it (e.g. because you have provided an invalid token)...?

In any case, is this issue valid for Drupal 8 also? If so, it would need to go there first, then backported.

cashwilliams’s picture

I think we should follow the path set by the just committed #927138: Fail image generation with 404 instead of 500, when source file is missing

cambraca’s picture

Should we mark this as duplicate then? I'm not too familiar with the process, I couldn't tell if that other issue's code is already in the 7.x dev branch, if so then this issue is no longer relevant and should be closed. Right?

cashwilliams’s picture

No, it's separate. It addresses the actual image missing, where as this addresses the wrong token.

Dane Powell’s picture

Version: 7.x-dev » 8.0.x-dev
FileSize
3.29 KB

I confirmed this issue still exists in Drupal 8. Oddly, the test case appears to already test for a 404- I don't know how it was passing in the first place.

Here's a patch against 8.0.x-dev, functionally identical to the 7.x version in #4.

Status: Needs review » Needs work

The last submitted patch, 13: drupal-2211429-13.patch, failed testing.

Status: Needs work » Needs review

Status: Needs review » Needs work

The last submitted patch, 13: drupal-2211429-13.patch, failed testing.

Status: Needs work » Needs review
Dane Powell’s picture

Umm... I have no idea why tests are repeatedly failing. Each time it's with a different error- none of them seem related to the patch.

Edit: tests are passing now.

mgifford’s picture

Status: Needs review » Needs work
Truptti’s picture

FileSize
73.7 KB

The patch 'drupal-2211429-13.patch' in comment #13 is not applied and gives error.
Attaching snapshot for referenc

mgifford’s picture

Issue tags: +Needs reroll

Agreed @Truptti - a lot can change in 9 months. You up for trying to re-roll this patch?

ajalan065’s picture

Rerolled the patch, and it worked for me..Rest on the Test Bot

ajalan065’s picture

Status: Needs work » Needs review
anavarre’s picture

Issue tags: +scalability
heykarthikwithu’s picture

On applying patch, i am getting warnings
warning: core/modules/image/src/Controller/ImageStyleDownloadController.php has type 100644, expected 100755
warning: core/modules/image/src/Tests/ImageStylesPathAndUrlTest.php has type 100644, expected 100755

root@ubuntu:/var/www/d8# git apply -v Incorrect-url-image-2211429-22-8.patch
Checking patch core/modules/image/src/Controller/ImageStyleDownloadController.php...
warning: core/modules/image/src/Controller/ImageStyleDownloadController.php has type 100644, expected 100755
Checking patch core/modules/image/src/Tests/ImageStylesPathAndUrlTest.php...
warning: core/modules/image/src/Tests/ImageStylesPathAndUrlTest.php has type 100644, expected 100755
Applied patch core/modules/image/src/Controller/ImageStyleDownloadController.php cleanly.
Applied patch core/modules/image/src/Tests/ImageStylesPathAndUrlTest.php cleanly.
royal121’s picture

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

Drupal 8.2.0-beta1 was released on August 3, 2016, which means new developments and disruptive changes should now 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.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.

basvredeling’s picture

Did a quick test of #26. Seems to work as intended.

akashkrishnan01’s picture

Patch #26 has been tested and working fine

LoMo’s picture

Status: Needs review » Reviewed & tested by the community

Also (manually) tested #26 and can confirm that it seems to work fine. :-) Since automated tests also appear to be in place, look correct (and pass), I think this can be marked RTBC. It would be nice to see this committed before it needs another re-roll. ;-)

catch’s picture

Discussed this with @alexpott a bit, we disagreed on the solution somewhat, so trying to document my take on the 404 vs. 403 here. Alex's point of view was that we should 403 if the file could be generated but we're refusing, and 404 when it's not there (this is not our current behaviour when we have a bad itok and also a missing file).

There are several scenarios. The first value in parenthesis is the current behaviour, the second is what the patch changes it to (if there's a change).

1. Valid itok + derivative on disk (200)
2. Invalid/no itok + derivative on disk + source image (200)
3. Invalid/no itok + derivative on disk + no source image (200)
4. Valid itok + source image (200)
5. Valid itok + no source image (404)
6. Invalid itok + source image (403) (404) - we check the itok before checking file_exists() and return early
7. Invalid itok + no source image (403) (404)

For me, given that any other request with a correct itok will result in a valid image on disk that's then accessible, we should not treat the itok check as an access check as such, but just determining whether something (the generated file) is going to be returned by that location or not, which only needs to happen when it's not already there.

The only reason to stick to a 403 semantically here would be if we weren't using on-disk derivatives at all but were access checking the files each time, but that's not what the itok is for - it's only a protection against DDOS.

Given that links with and without the itok are fairly common, the existence of the file on disk may or may not be determined by the request at all - it's simply there or it isn't, and if it isn't only then does the itok matter. So a 404 seems fine.

alexpott’s picture

Given #32 I think that returning a 404 is reasonable.

alexpott’s picture

Status: Reviewed & tested by the community » Needs work
+++ b/core/modules/image/src/Controller/ImageStyleDownloadController.php
@@ -109,7 +112,7 @@ public function deliver(Request $request, $scheme, ImageStyleInterface $image_st
-      throw new AccessDeniedHttpException();
+      throw new NotFoundHttpException();

I think some commentary why we return a 404 here for invalid itok's. Something like at this point we don't know if the source file exists on the server and in order to minimise disk activity we don't bother to check. Because we already know that we're going to return an error response and we chose a 404 because it is cacheable. Or something like that. Or borrow some of the words from #32

LoMo’s picture

Assigned: Unassigned » LoMo

Okay. I'll get a patch together with the needed commentary for review. I think this is a good way to avoid regression (even more appropriate than just updating the tests to our current behavior). I'll include a reference to this issue.

LoMo’s picture

Assigned: LoMo » Unassigned
Status: Needs work » Needs review
FileSize
5.08 KB

Hopefully this fits the bill and we can just get this committed after 3 years. ;-)

akashkrishnan01’s picture

LoMo’s picture

@akashkrishnan What?

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

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

anavarre’s picture

Rerolled against 8.6.x as it no longer applied.

anavarre’s picture

Title: Incorrect image url, using an image style, should return a 404 instead of a 403 » Incorrect image URL using an image style should return a 404 instead of a 403
Issue summary: View changes

Updated the issue summary and wrote an initial draft for a change record as I think this would be helpful to advertise for this change when it lands.

mcdruid’s picture

In the change record, I'd suggest:

upon trying to access an invalid image token derivative or an invalid image token with no source image available

...should instead be:

upon trying to access an image derivative with an invalid token, whether or not the source image is available

(I think the same text would be changed in both the before and after section.)

I'd perhaps also change "load balancer" for something like "caching reverse proxy" or just "caching proxy".

anavarre’s picture

anavarre’s picture

Quickly discussed the issue with @mcdruid and he suggested an improved comment and few other CR changes.

Core committers: please make sure to credit him, thanks!

mcdruid’s picture

Status: Needs review » Reviewed & tested by the community

I think the patch looks good, tests pass, and the CR makes sense. RTBC!

Wim Leers’s picture

Issue tags: +D8 cacheability

👍

mcdruid’s picture

Issue tags: +Security improvements

Adding "Security improvements" tag, as this is about enhancing resilience to (D)DoS.

alexpott’s picture

Status: Reviewed & tested by the community » Fixed

Crediting @catch, @cashwilliams and @mcdruid as per comments and reviews.

diff --git a/core/modules/image/src/Controller/ImageStyleDownloadController.php b/core/modules/image/src/Controller/ImageStyleDownloadController.php
index 7be5f870fd..3d4ee1cc81 100644
--- a/core/modules/image/src/Controller/ImageStyleDownloadController.php
+++ b/core/modules/image/src/Controller/ImageStyleDownloadController.php
@@ -111,7 +111,6 @@ public function deliver(Request $request, $scheme, ImageStyleInterface $image_st
       // image token is for DDoS protection rather than access checking. 404s
       // are more likely to be cached (e.g. at a proxy) which enhances
       // protection from DDoS.
-      // @see https://www.drupal.org/node/2211429
       throw new NotFoundHttpException();
     }
 

Removed @see on commit because git history gives you this. The @see to an issue nid is pointless.

Backported to 8.5.x since this has caused issues on real sites.

  • alexpott committed 8f8942b on 8.6.x
    Issue #2211429 by anavarre, cambraca, LoMo, ajalan065, Dane Powell,...

  • alexpott committed 5db6ae1 on 8.5.x
    Issue #2211429 by anavarre, cambraca, LoMo, ajalan065, Dane Powell,...
anavarre’s picture

Thanks! Published the CR.

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.