Uploading files breaks drupal page cache

Created on 26 May 2025, 5 days ago

Problem/Motivation

Not sure if that is really a bug or a feature request, but when an anonymous user uploads a file to a form, the Drupal page cache stops working. This is caused by anonymous_allowed_file_ids being set for the anonymous user session, allowing the anonymous user access to the uploaded file. The created session then breaks the Drupal page cache, since Drupal\Core\PageCache\RequestPolicy\NoSessionOpen automatically denies the page cache for all users that have a session.

Steps to reproduce

  1. Enable the page cache module.
  2. Visit a page and verify the page can be served from the page cache.
  3. Create a form with a file upload field, configured to upload private files.
  4. Upload a file to the form as an anonymous user.
  5. The page that was previously served from the cache, is now no longer cached.

Proposed resolution

Not sure what would be the best way. It seems uploading and submitting the form still works even when the user does not have access to the file. I guess we could:

  1. Add a flag to the file fields to make creating a session optional per field.
  2. Add a generic option the the site to disable creating sessions for users in all file fields.
  3. Maybe create a permission that can be enabled for the anonymous user role: "Access own files".

Remaining tasks

  1. Discuss the best way to move forward.
  2. Write a patch
  3. Write tests
  4. Review
  5. Commit

User interface changes

TBD

Introduced terminology

None

API changes

TBD

Data model changes

TBD

Release notes snippet

TBD

✨ Feature request
Status

Active

Version

11.2 πŸ”₯

Component

file system

Created by

πŸ‡³πŸ‡±Netherlands seanB Netherlands

Live updates comments and jobs are added and updated live.
Sign in to follow issues

Merge Requests

Comments & Activities

  • Issue created by @seanB
  • πŸ‡³πŸ‡±Netherlands seanB Netherlands

    Personally I kind of like the idea of having a permission for this. Added an MR for review.
    This definitely needs more tests though if this is the way we want to go.

  • πŸ‡³πŸ‡±Netherlands seanB Netherlands
  • Pipeline finished with Failed
    5 days ago
    Total: 4356s
    #506858
  • πŸ‡ΊπŸ‡ΈUnited States smustgrave

    Can the MR be updated for 11.x as the main development branch

  • This was added to fix "Files uploaded by anonymous users into a private file system can be accessed by other anonymous users" in SA-CORE-2017-003 β†’ .

  • πŸ‡¨πŸ‡­Switzerland znerol

    git log -S anonymous_allowed_file_ids indicates that this mechanism has its origins in SA-CORE-2017-003 β†’ (Files uploaded by anonymous users into a private file system can be accessed by other anonymous users).

    https://git.drupalcode.org/project/drupal/-/commit/c732355412b84a6f7079d...

    The code comment at the top of the relevant hunk reads:

            // This case handles new nodes, or detached files. The user who uploaded
            // the file can always access if it's not yet used.
    

    This indicates that this branch in anonymous_allowed_file_ids">FileAccessControlHandler::checkAccess() is only reached as long as the parent entity (e.g. media) is not saved yet.

    I think that the file id should be cleared from the anonymous_allowed_file_ids session value as soon as the temporary upload file is moved to permanent storage. If anonymous_allowed_file_ids becomes empty, then it needs to be removed from the session. And as soon as the whole session is empty, it will be destroyed automatically.

  • πŸ‡¨πŸ‡­Switzerland znerol

    Something like this could go into a response subscriber:

    $fids = $session->get('anonymous_allowed_file_ids', []);
    if (!empty($fids)) {
      $fids_unref = [];
      $files = $this->fileStorage->loadMultiple($fids);
      foreach ($files as $file) {
        $references = $this->fileUsage->listUsage($file);
        if (empty($references)) {
          $fids_unref[] = $file->id();
        }
      }
      if (empty($fids_unref)) {
        $session->remove('anonymous_allowed_file_ids');
      }
      else {
        $session->set('anonymous_allowed_file_ids', $fids_unref);
      }
    }
    

    You can try this in a custom module as a quick fix until somebody comes up with a clever approach.

  • πŸ‡³πŸ‡±Netherlands seanB Netherlands

    Thanks, I'll try that! The only case this doesn't work is when the user aborts after the file is uploaded. The entity the file is being attached to is never saved and the file will remain temporary as long as defined in system.file:temporary_maximum_age.

    For now I will test the response subscriber and probably add something custom to remove the files for anonymous users after a short period of time. Hopefully someone can think of a better way to clean the sessions for those cases!

    I'll also close the MR for now, the branch was wrong and the approach is probably to complex.

Production build 0.71.5 2024