Problem/Motivation

The filter Restrict images to this site checks if an image is local by trying to load image dimensions from the local file, if that fails, the image is marked as remote and removed from the markup:

      // Ensure the path refers to an actual image by prefixing the image source
      // with the Drupal root and running getimagesize() on it.
      $local_image_path = $local_dir . Unicode::substr($src, $base_path_length);
      $local_image_path = rawurldecode($local_image_path);
      if (@getimagesize($local_image_path)) {
        // The image has the right path. Erroneous images are dealt with below.
        continue;
      }

That code breaks for private:// files, because the image URL looks something like /system/files/inline-images/search.jpg, but that directory does not exist on disk.

It also breaks when using image style derivatives (particularly an issue when using a module like entity embed). The URL to the image includes a token as a query parameter, and this token is still present when checking for the file on the file system.

Steps to reproduce

- Set up Drupal 10/11.
- Edit the "Basic HTML" text format and set the file storage of uploaded images to "Private local files served by Drupal.". Ensure that the "Restrict images to this site" filter is enabled.
- Create a node of type "Article".
- Upload an image into the body field (with the "Basic HTML" text filter) and save the node.
- Open the just created node and observe that the image will be removed for security reasons, although it is stored locally.
Screenshot of issue

Proposed resolution

Adapt the "Restrict images to this site" filter to be able to also handle private files.

Remaining tasks

- Code Review

User interface changes

None. (Well, working private images.)

API changes

None.

Data model changes

None.

Issue fork drupal-2528214

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

jastraat’s picture

This means that the entity embed module cannot display images for view modes that are using an image style.

jastraat’s picture

This isn't terribly elegant, but what about adding

// Check for query string and remove it if present.
$parse_query_string = substr($local_image_path, 0, strpos($local_image_path, '?'));
if (!empty($parse_query_string)) {
  $local_image_path = $parse_query_string;
}

to _filter_html_image_secure_process() to strip the query string before calling @getimagesize($local_image_path) ?

This worked in my situation.

jastraat’s picture

StatusFileSize
new881 bytes

Patch attached

jastraat’s picture

Status: Active » Needs review

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.

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.

hongpong’s picture

When trying to reference an image from a Javascript, I am running into 403 forbiddens, I'm assuming because that image style is not referenced from a view in a 'hard coded' way and it's not giving a good token. Posting on this thread because this is a prominent search result for it. Forcing through the image reference, preventing the forbidden, would be nice.
Ah see also: https://www.drupal.org/node/1923814

... and via David Rothstein here #1934498: Allow the image style 'itok' token to be suppressed in image derivative URLs:
The particular configuration setting added to Drupal 8 in this issue can be enabled via $config['image.settings']['suppress_itok_output'] = TRUE in settings.php followed by a cache clear. However, images in Drupal should not be broken just because there are tokens in the path.... So instead of suppressing the tokens and lowering security, it would make more sense to debug what is breaking them.

wim leers’s picture

wim leers’s picture

wim leers’s picture

Issue summary: View changes
wim leers’s picture

boobaa’s picture

The patch in #2772617: Handle files uploaded to the private storage as internal looks more proper to me - should it be added to this issue, too?

thpoul’s picture

StatusFileSize
new1.59 KB
jastraat’s picture

Does the private file patch actually address the issue with image style derivatives though? Those are in the public files directory generally, and the problem is due to the query string token appended to the image path.

You changed the description to eliminate the actual issue this was created to report.

jastraat’s picture

Issue summary: View changes
beatnbite’s picture

I've tried to create a filter that replaces inline images with their style derivatives and face the same problem: "getimagesize($local_image_path)" fails due to the "itok" parameter in the path to the image; as a results the images are considered invalid.

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.

eigentor’s picture

I tried the patch from #3. It worked for some images, but some were still removed. Tested using Entity Embed in CKeditor.

nathaniel’s picture

Combining patches.

#3 image_restrict_image_styles-2528214-3.patch
Image style derivatives.

#13 2528214-13.patch
Private images.

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.

wim leers’s picture

Note this is also blocking contrib now:

wim leers’s picture

This still needs tests for sure.

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.

kingdutch’s picture

StatusFileSize
new2.13 KB
new830 bytes

Due to the variable naming in this patch it could occur that the alter hook triggered in the _filter_html_image_secure_process function was passed an object that implemented ImageInterface instead of a DOMElement which causes errors when filter_filter_secure_image_alter tries to call setAttribute.

We've been unable to find the exact replication steps but if you follow the code you can see where it happens:

Line 799 and 780 do the following.

      $image = \Drupal::service('image.factory')->get($private_image_path);
      if ($image->getFileSize()) {
        // The image has the right path. Erroneous images are dealt with below.
        continue;
      }

Before this the $image variable contained a DOMElement instance. If the $image->getFileSize() returns TRUE then everything is okay as the alter hook on line 825 will not get invoked.

\Drupal::moduleHandler()->alter('filter_secure_image', $image);

However, if the getFileSize() call returns NULL or 0 (both valid values according to the ImageFactory::get documentation) then the continue is not invoked and the alter hook is now called with an \Drupal\Core\Image\Image object instance.

The attached patch renames the loaded image object so that the DOMElement remains intact for the alter hook.

efpapado’s picture

#24 works for 8.4.5, but I don't set it to RTBC since testing needs to be done in 8.5.x

madt’s picture

Patch #24 does not work for 8.5.3 for embedded images with image styles.

borisson_’s picture

Status: Needs review » Needs work

Like Wim said in #22, this needs tests.

johnzzon’s picture

A tip when using entity embed, place "Display embedded entities" after "Restrict images to this site" in the "Filter processing order" for your text format. That way the Restrict images will run before embedding the entity (the image), and thus not affecting it.

jofitz’s picture

Status: Needs work » Needs review
StatusFileSize
new2.59 KB
new4.72 KB

Added tests. No interdiff because the only changes are in the test_only patch.

I'm continuing to work on the 8.5.x patch because that is the version I require, but I will re-roll for 8.6.x too once the patch is stable.

The last submitted patch, 29: 2528214-29-test_only.patch, failed testing. View results

Status: Needs review » Needs work

The last submitted patch, 29: 2528214-29-complete.patch, failed testing. View results

jofitz’s picture

Status: Needs work » Needs review
StatusFileSize
new814 bytes
new4.24 KB

Correct the test_only patch (I have a suspicion that this might pass when it should fail, but I can't run functional tests locally).

Status: Needs review » Needs work

The last submitted patch, 32: 2528214-32.patch, failed testing. View results

jofitz’s picture

Status: Needs work » Needs review
StatusFileSize
new814 bytes
new2.61 KB
new4.74 KB

#32 was full of mistakes, so let's pretend that never happened!

The last submitted patch, 34: 2528214-34-test_only.patch, failed testing. View results

jofitz’s picture

StatusFileSize
new4.7 KB

Patch in #34 no longer applies. Re-rolled.

Status: Needs review » Needs work

The last submitted patch, 36: 2528214-36.patch, failed testing. View results

jofitz’s picture

Status: Needs work » Needs review

Ignore the patch in #36 that was rolled against 8.6.x.

biguzis’s picture

Status: Needs review » Needs work

This still not working properly. When I used file which has whitespace in name (e.g. file name.png) image ends up as removed. When renaming file to filename.png and re-uploaded, it showed up as expected. URL in first case contains %20 and probably this is causing issue? I did't really looked in code, sorry. Most probably some small fix is needed.

biguzis’s picture

StatusFileSize
new4.83 KB
new770 bytes

I added simple str_replace(). Probably not best solution for all cases (special char cases maybe, e.g. š, ņ, ē), but currently fix issue for me.

robertragas’s picture

@biguzis
Thanks for the patch! I was using #24 which at least solved wsod, but still has the same problem as you describe and your patch works for that.
Like you say I also think there are better solutions than the str replace. Doesn't Drupal offers a sanitize function that will strip it the correct way?

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.

oriol_e9g’s picture

Patch in #40 not longer applies in Drupal 8.6.x.

jofitz’s picture

Status: Needs work » Needs review
StatusFileSize
new4.78 KB

Re-rolled.

Status: Needs review » Needs work

The last submitted patch, 44: 2528214-44.patch, failed testing. View results

jofitz’s picture

Status: Needs work » Needs review
StatusFileSize
new548 bytes
new4.77 KB
robertragas’s picture

StatusFileSize
new4.76 KB

Added a new patch as an addition to #40, where I altered the str_replace by urldecode, this should offer a more wide range instead of just the %20

wim leers’s picture

Issue tags: +Media Initiative
codeyourdream’s picture

Note that because of the call to getimagesize() none of these patches work in case when the derivative doesn't exist at the time when the filter is applied.
I.e.:
- "public://my-image.jpg" exists.
- "/sites/default/files/styles/thumbnail/public/my-image.jpg" doesn't.

ptmkenny’s picture

Status: Needs review » Needs work

Marking this as "needs work" based on #49.

wim leers’s picture

none of these patches work in case when the derivative doesn't exist at the time when the filter is applied.

Exactly. This is still a problem.

- "/sites/default/files/styles/thumbnail/public/my-image.jpg" doesn't.

This is the case that we run into in the Entity Embed contrib module, see #2752253-8: Document correct filter_html_image_secure + filter_align + filter_caption + entity_embed filters order, write tests, and ensure correct by default.

wim leers’s picture

@marcoscano pointed out while discussing this in #2752253: Document correct filter_html_image_secure + filter_align + filter_caption + entity_embed filters order, write tests, and ensure correct by default that it actually doesn't make sense for this filter to be filtering <img src=…> that wasn't entered by the content author: if that HTML is imported from other content on the site (transcluded, embedded …), then it shouldn't be ignoring (i.e. not securing) the transcluded HTML.

This is a way we could achieve that.

epapaniko’s picture

StatusFileSize
new4.77 KB

I'm adding a patch based on #47, because it does not work with private paths for installations under a directory, ie http://example.com/drupal/folder as mentioned in the definition of base_path().

The only difference is that I removed the hard-coded leading slash of $private_path and replaced it with $base_path.

devkinetic’s picture

StatusFileSize
new1.49 KB

I just ran into this issue and read through the queue. Here is a swing at ignoring embedded media by way of inspecting the data attributes on the <img> tag. This has resolved our use case of using the wysiwyg to place private images on a content type.

wim leers’s picture

@devkinetic: How are you embedding Media? Because #2940029: Add an input filter to display embedded Media entities and https://www.drupal.org/project/entity_embed both specifically ensure that their filters run after filter_html_image_secure, meaning that they are not adversely impacted by this.

So, I think you're referring specifically to images as inserted by EditorImageDialog? Those are not "media" as in Media entities.

(I know, Drupal's terminology is confusing here!)

devkinetic’s picture

@Wim Yes we are placing private files, and the getimagesize() failes on the /inline-images/ route.

wim leers’s picture

Alright 👍

While #56 would work for those image URLs, it still won't solve the general problem. The general problem was being fixed in earlier patch iterations.

(My patch in #53 should also be ignored, it was also addressing a different, related problem, that now no longer is a problem.)

bkosborne’s picture

Ok so like 90% of the issues people report with this issue is that it fails when attempting to validate that the image actually exists. Has no one asked why the filter is even doing this check? I think the filter should just verify that the path to the image is local and that's it!

The description of the filter:

Disallows usage of <img> tag sources that are not hosted on this site by replacing them with a placeholder image.

I vote just removing the file exists check altogether.

As a site owner, I just want to ensure that images don't have sources from other websites. Full stop.

devkinetic’s picture

There is a bit of gray area… Does this filter show the red X on images missing from existence? Or does this filter show the red X when an image is referenced from an external location?

These are really two totally different cases, but as a site owner, I would really want the same red X functionally for both cases. I’d also want to ensure that I’m getting proper 404 logging for both cases, so they can be tracked down and fixed.

The filter description would be more like, “Replace <img> tags with a placeholder image when missing or externally hosted.”

The code would have to be modified to handle both cases individually, but treat them the same.

- missing public files
- missing private files
- externally hosted

bkosborne’s picture

I think that this could be solved by adding settings for the filter. Have a checkbox "Verify that image exists". We would have it checked by default for backwards compatibility. But turning it off would allow people who want to link to image style derivs and private files to still use the other portion of the filter.

If I get some agreement from others, I can update the issue summary and title to reflect that change.

devkinetic’s picture

We would still want to verify that a private file exists. As well as for image styles, we’d want to verify that the source image exists to build the derivative. If that checkbox handled this too, I’d agree.

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

Drupal 8.6.x will not receive any further development aside from security fixes. Bug reports should be targeted against the 8.8.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.9.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.

james.williams’s picture

StatusFileSize
new4.82 KB

Here's a re-rolled version of patch 55 (which itself was a tiny adjustment to patch 47). Sorry that excludes any of the other progress/thoughts since comment 47. This is just for anyone else like me that was using patch 47 on a site that needed upgrading.

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

Drupal 8.8.7 was released on June 3, 2020 and is the final full bugfix release for the Drupal 8.8.x series. Drupal 8.8.x will not receive any further development aside from security fixes. Sites should prepare to update to Drupal 8.9.0 or Drupal 9.0.0 for ongoing support.

Bug reports should be targeted against the 8.9.x-dev branch from now on, and new development or disruptive changes should 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: 8.9.x-dev » 9.2.x-dev

Drupal 8 is end-of-life as of November 17, 2021. There will not be further changes made to Drupal 8. Bugfixes are now made to the 9.3.x and higher branches only. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

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

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

Drupal 9.3.15 was released on June 1st, 2022 and is the final full bugfix release for the Drupal 9.3.x series. Drupal 9.3.x will not receive any further development aside from security fixes. Drupal 9 bug reports should be targeted for the 9.4.x-dev branch from now on, and new development or disruptive changes should 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.4.x-dev » 9.5.x-dev

Drupal 9.4.9 was released on December 7, 2022 and is the final full bugfix release for the Drupal 9.4.x series. Drupal 9.4.x will not receive any further development aside from security fixes. Drupal 9 bug reports should be targeted for the 9.5.x-dev branch from now on, and new development or disruptive changes should 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.

ericras’s picture

StatusFileSize
new4.83 KB

Reroll for 10.1

damienmckenna’s picture

In case anyone else runs into a similar problem - a site was showing a symptom like this, only the problem turned out to be a custom URL processor that was changing all image paths of a certain type from "public" to "private", regardless of where the source image was. After far too much time was spent digging through the problem, removing the few lines of custom code fixed it and the images loaded again. X-|

Version: 9.5.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. For more information, see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

nico.b made their first commit to this issue’s fork.

nico.b’s picture

Status: Needs work » Needs review
Issue tags: -Needs tests

I've converted the patch from #71 to a MR to comply with current Drupal processes. Tests are successful and test-only changes show that the test will fail without the fix.

smustgrave’s picture

Status: Needs review » Needs work
Issue tags: +Needs issue summary update

Have not reviewed yet but the issue summary appears to be incomplete,

Appears to be missing steps to reproduce section too

nico.b’s picture

Issue summary: View changes
Status: Needs work » Needs review
Issue tags: -Needs issue summary update
StatusFileSize
new10.29 KB

Adapted the issue description and added steps to reproduce.

catch’s picture

Status: Needs review » Needs work

Couple of comments on the MR.

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.