DiggingIntoWordPress

by Chris Coyier & Jeff Starr

How to Setup Secure Media Uploads

Posted by on

As discussed, it’s important to protect your site by setting proper file permissions on the server. This can be tricky for certain directories such as /uploads/, /upgrade/, and /backups/, which need to be writable by the server in order for things like uploads, upgrades, and backups to work.

On the one hand, you want the most restrictive permissions possible for security reasons, and in most cases the default/recommended settings for directories such as /uploads/ work just fine. On the other hand, if your directory permissions are too restrictive, things like media-uploads stop working.

The good news is that we can have the best of both worlds: solid security for writable directories and suitable file-permissions for working uploads, upgrades, and backups. In this tutorial, you’ll learn how to use .htaccess to secure WordPress’ /uploads/ directory or just about any other directory, WordPress or otherwise.

Securing directories with .htaccess

In my experience studying server logs, WordPress’ /uploads/ directory is heavily targeted by malicious scripts and bots. Unfortunately, some server configurations require 777 permissions in order for stuff like Media Uploads to work. Of course, that’s never a good idea, so let’s lock down those vulnerable directories with a bit of .htaccess.

Note that this technique is written for use in .htaccess files, but is better implemented via Apache’s main configuration file (httpd.conf). If you don’t have access to configuration files or prefer to localize via .htaccess, the following technique will make it happen.

Step 1: Create an .htaccess file for your /uploads/ directory (or use existing file if present). In it, place the following code and upload to your server:

# secure uploads directory
<Files ~ ".*\..*">
	Order Allow,Deny
	Deny from all
</Files>
<FilesMatch "\.(jpg|jpeg|jpe|gif|png|tif|tiff)$">
	Order Deny,Allow
	Allow from all
</FilesMatch>

This denies access to all files but then allows access only to the specified types of images. If you’re working with other media types such as .zip, .mp3, .mov, or whatever, simply edit the FilesMatch pattern like so:

(jpg|jpeg|jpe|gif|png|tif|tiff|zip|mp3|mov)

Likewise you can remove anything that you won’t be using. This is the key to implementing this technique in other directories such as /upgrade/, /backup/, and so forth. Once in place, this technique prevents bad guys from injecting any PHP or other scripts, but allows images (and/or other specified file types).

Other things to try

If you’re trying to get media-uploads to work but don’t want to go all 777 on the server, here are some other, more round-about things to try:

  • experimenting with incrementally more secure permissions until something works
  • disabling PHP Safe Mode
  • unchecking the auto-organization year/month option
  • trying different file paths
  • switching hosts if possible

I’ve experimented with all of these tactics in various server environments, but it’s generally hit-or-miss — works or it doesn’t. Some alternate solutions/workarounds aren’t as secure as others, so if you’re stuck with 777 permissions, the previous .htaccess technique will help secure your /uploads/ directory against malicious scripts and other nefarious behavior.

Shameless plug! If you enjoy .htaccess techniques like the one in this article, check out my new book, .htaccess made easy — Thank you!

7 Responses

  1. Thanks for the code and your .htaccess book – both are awesome :)

  2. congrats on the new book release!

  3. Thank you guys! It is much appreciated :)

  4. I was planning to let my visitors upload pictures but I was hesitating to do this due to security issues. I will try your method. Thanks.

  5. Nice secure media upload…
    thanks for posting information..

  6. Great informations but why a default installation of WordPress doesn’t come already secured?

  7. Its a cool feature. Thanks for sharing :)

Comments are closed. Contact us with any critical information. Thank you!

Code is poetry