by David Snopek on January 17, 2018 - 10:21am

One of the great things about Drupal, is that it's possible to build a pretty advanced site just by pointing and clicking and configuring things - what we call "site building" in the Drupal universe.

But with all that power, you can also make your Drupal site less secure - and possible to hack! - just by changing configuration settings! We covered other examples of this in a previous article.

Today we're going to talk about one of the most common... and most DANGEROUS: exposing your Drupal private files on the internet.

In this article we're going to discuss how to determine if your private files have been exposed, and also how to fix it.

Read more to find out!

What are Drupal "private files"?

On all Drupal sites, there are at least two different types of files: public and private.

Public files are served directly by the web server, which is nice because it's fast. Private files have to pass through Drupal, which is slower, but allows Drupal to define the rules to access them.

Private files are usually used for either:

  1. User uploaded content you want to control access to (ex. a newsletter than only site members should be able to see), or
  2. Files created by Drupal modules which they intend to keep private, usually for security reasons

You probably know if you have #1, but you might not know if you have #2 if you don't know how all the modules on your site work.

So, even if you're not using private files to power a feature of your site, a module that you use may be using them unbeknownst to you! Because of that, it's always important to make sure your private files aren't being exposed to the internet.

How does Drupal keep private files private?

Public files have to be placed in your public "web root" along with the other files that make up your Drupal site, so that the web server can serve them.

Private files should either:

  1. Be placed outside the web root, where the web server can't get to them, or
  2. If they are in the web root, you need to configure your webserver not to serve them

#1 will always be safe!

It's #2 where things can go wrong. Frequently, private files are placed within the web root (ex. under "sites/default/files/private") but without changing the web server configuration to prevent directly accessing them, and skipping Drupal altogether.

How to find out if they are exposed?

This is pretty easy to check manually, but does require a little bit of Drupal and technical know how:

  1. Login to your Drupal site as an admin user
  2. Go to Configuration -> Media -> File system
  3. Check the "Private file system path"
  4. If you it might be in the web root, then place a file at the given path (probably will require using FTP or SSH to transfer a file to the live server) and then try to access it with your web browser. For example, if your "Private file system path" is "sites/default/files/private" then upload a "test.txt" file and try to access it at http://example.com/sites/default/files/private/test.txt
  5. If you can access the file directly - then your private files are exposed to the internet!

Since that involves messing around with FTP or SSH, an easier way may be installing the Security Review module and running its report. It'll find exposed private files as well as a number of other potential security issues with your site!

How to fix it?

The safest thing you can do is to move your private files directory outside the web root. If your site is at the top-level of your domain, an easy option can be putting the private files at a directory above the web root.

For example, if you login to Drupal by going to http://example.com/user/login as opposed to some prefix directory like http://example.com/drupal/user/login, then you know that your site is at the top-level of your domain, so there shouldn't be any way to access files in the directory above it.

Here's the process:

  1. Use FTP or SSH to move the private files directory to a "sibling" directory to your Drupal root, for example, called "private"
  2. Login to your Drupal site as an admin user
  3. Go to Configuration -> Media -> File system
  4. Change the "Private file system path" to a path relative to the Drupal root, starting with "..", for example, "../private"
  5. Click "Save configuration"

An alternative to this is changing the configuration of your web server to block access to files in the private files directory, but that can be tricky - it depends on your specific web server (Apache, nginx, IIS) and configuration. So, we're not going to go into that today - that could be the topic for a whole new post. :-)

Conclusion

If you have a Drupal site, you need to make sure that your private files are secure - even if you think you don't have any private data on your site, you could be surprised!

Hopefully, the steps above will be helpful, even for users who aren't very technical. Unfortunately, though, maintaining a website will always be at least a little technical, so you may need to call on an expert!

If you have any questions or feedback or tips, please leave them in the comments below!

Or, if you're interested in paid support: Our whole business is support and maintenance for Drupal sites, so if you need help, please feel free to contact us. Good luck!

Want to read more articles like this?

myDropWizard.com blog Subscribe to the myDropWizard.com blog and recieve e-mail updates when new articles are published!

Comments

Hi David,

Timely article. I was just working on this. Two questions:

1. If you are using the file_entity moudle on a site where you want to move files from public:// to private:// is it also necessary to run an sql update like this:

$query = db_select('file_managed', 'fm')
->fields('fm', array('uri'))
->condition('filename', $filename)
->execute();
$uri = $query->fetchField();

if (preg_match('@^public://@', $uri)) {
$rows_updated = db_update('file_managed')
->condition('filename', $filename)
->expression('uri', "REPLACE(uri, 'public://', 'private://')")
->execute();
if ($rows_updated >= 1) {
drupal_set_message(dt('@file: Updated file_managed.url value.', array('@file' => $filename)));
}
else {
drupal_set_message(dt('@file: Failed to updated file_managed.url value.', array('@file' => $filename)), 'error');
}
}
}

I couldn't quickly determine if this module had magic in it that would detect the fact that I'm moving to private:// and update these records for me.

2. Clearly using private:// is more secure, but I've always wondered: If files are public, but there is no public page that links to them and you can't get a directory listing in the browser by visiting the public path, how might these files be discovered? Do web crawlers have some sneaky way of finding them?

1. If you are using the file_entity moudle on a site where you want to move files from public:// to private:// is it also necessary to run an sql update like this:

Good question! I just tested it on a vanilla Panopoly 1.49 site, and editing a File entity and changing the "Destination" from public to private moved it on the file system, and updated the uri to start with private://

So, it seems the file_entity module has you covered!

2. Clearly using private:// is more secure, but I've always wondered: If files are public, but there is no public page that links to them and you can't get a directory listing in the browser by visiting the public path, how might these files be discovered? Do web crawlers have some sneaky way of finding them?

If there are no public links to the files, and the webserver won't give a directory listing, and the file names are completely unguessable - then no one will be able to find them.

However! In real life:

  • Links can leak out - usually via a user error. A client just told me a story about how the dev environment of their new, unfinished site got attacked when a member of his team (not a developer, just someone working at this nonprofit) posted a link on Facebook to show off how the new site will look :-)
  • The webserver can accidentally get misconfigured (either initially, or at some point later) to show directory listings, and it's possible to craft queries for Google to find webserver directory listing pages, meaning that pretty much anyone can discover them with very little sophistication
  • And if the files are being saved by a module (not a human) then the URL's can be guessable. If you know it's "module/date.txt" or similar, you can just start at today's date and work backward until you find something. Not many sites have a WAF or other monitoring to block excessive similar requests and will just let an attacker keep trying different variations forever

So, if you have data that's private that you don't want exposed to the internet, it's best to play it safe and put it in the private filesystem (and to make sure that's secure too)

> editing a File entity and changing the "Destination" from public to private moved it on the file system, and updated the uri to start with private://

Right, that works on an entity-by-entity basis.

I should have asked the question like this:

1. If you are using the file_entity module on a site where you want to move <b>all existing files</b> from public:// to private:// is it also necessary to run an sql update like this (see above).

I believe the answer is "yes" you need to run that SQL after moving the files to the correct directory on the server filesystem. <b>Or alternatively</b> you can edit the destination setting on each file entity.

I believe the answer is "yes" you need to run that SQL after moving the files to the correct directory on the server filesystem.

Correct, if you move the files on disk without going through Drupal, you'll need to update the database for the new URI too.

Thanks
I ve done as described in drupal doc
And open social but the problem is that on public the private images and especially the images linked to profiles are encrypted and hidden substituted with an interrogative sign or a broken image.
I ve joked with the permissions but in vain.
i ' m still struggling.

Sorry you're having problems :-/ It hard to give more advice, I'd really need to try and fix it on your site. If you're interesting in getting some paid support from us, please check out our plans and send us an email at [email protected]!

Add comment

o