Skip to main content

Beware File::getFileUri()!

An article from ComputerMinds - Building with Drupal in the UK since 2005
9th Nov 2018

Ross Bale

Developer
Hey, you seem to look at this article a lot! Why not Bookmark this article so you can find it easily in the future?

I'll keep this short and sweet, but we thought this would be a useful tip to share with the world as a potential security issue with the combined use of File::getFileUri() and FileSystem::realpath().

Consider the following code excerpt :

$file = File::load($some_file_uri);

if ($file) {
  $uri = $file->getFileUri();
  $file_realpath = \Drupal::service('file_system')->realpath($uri);
}

Seems pretty harmless right? Load up the file from $some_file_uri , If we have a valid file then get the URI and then grab the real path.

Wrong (potentially, depending on what you do with $file_realpath).

If $file is a valid file, but for whatever reason the file is no longer physically located on disk, then $file->getFileUri() will return a blank string.

It turns out that passing this blank string $uri into \Drupal::service('file_system')->realpath($uri) will return the full webroot of your site!

Depending on what you were doing with said $file_realpath, it could then be a security issue.

We were handling a user webform submission and then sending the submission over to a CRM system... because $file_realpath was now the webroot of the site, then code that followed to archive the user submitted file ended up archiving the entire webroot and sending this over to the client's CRM system. 

Luckily in this instance, the archive was only ever available temporarily server side and then went directly to the clients own CRM system, but in another circumstance this could have easily been a very serious security issue.

Fortunately the fix is quite simple, ensure the the $uri returned from ->getFileUri() is valid by some method, before passing through realpath(). Here, I now validate the uri matches what I know it should be for the current webform submission.

if ($file) {
  $uri = $file->getFileUri();
  $webform_id = $webform->get('id');
  $submission_id = $webform_submission->get('sid')->getValue()[0]['value'];
  $valid_file_scheme = strpos($uri, 'private://webform/' . $webform_id . '/' . $submission_id . '/') !== FALSE;

  if ($valid_file_scheme) { 
    // Proceed with the rest of the code..
  }
}

 

Hi, thanks for reading

ComputerMinds are the UK’s Drupal specialists with offices in Bristol and Coventry. We offer a range of Drupal services including Consultancy, Development, Training and Support. Whatever your Drupal problem, we can help.