Password-protected downloads: plugins vs an easy custom solution

One of our clients posts PDFs for internal use on the corporate website. A section of the site is behind a WordPress login, and all the national sales reps have access to it. They can post media in relative security on a page where everyone in regional offices can view them as needed.

However, although the page on which the media is displayed is behind a WordPress login, the media itself is served from a URL such as http://www.yoursite.com/uploads/2013/05/file.pdf. Anyone who knows the actual URL of the media can bookmark or email that link, then bypass the WordPress login to access and download the media directly.

Downloads from the server can be managed by editing .htaccess files in the media directory on the server. There are several WordPress plugins that provide protection for downloads with admin-panel editable .htaccess.

The first plugin we considered was: s2Member. This Member/roles plugin does download protection, and is only $69. Here’s a video about how it works: s2Member File Downloads. To set up download protection, you create a specific directory for the media, and put all the confidential media in there. This plugin is really for subscription content (with different membership “levels” rather than WordPress roles), so although it would work fine, it would require redoing all the existing user roles we had set up on the site. The client’s site uses Justin Tadlock’s Members plugin, which provides a simple interface for managing custom user roles. It does exactly what we need it to, and nothing more, and since the client manages their own site it was important to maintain this kind of simplicity. So s2Member was a little overkill for us. 

Next we looked at the Htaccess Secure Files plugin. It caused a fatal error when it was installed, so we did the usual tweaking: deactivate other plugins, poke around… after 10 minutes of trying to get it to work we gave up on it.

By this point we’d decided that a simple custom-built solution would work best with our existing plugins and let us keep things easy for the client. So we set up a custom .htaccess file to protect file downloads. These are the rules the server follows:

  1. The server can detect whether or not a user is logged into WordPress
  2. The server can look for a certain pattern in the filename. It can be anything you want, but it has to be consistent.
  3. If the user is trying to download a file whose filename contains the certain pattern, and they are not logged in, it will not allow access to the file.

It can’t distinguish between different user roles, and you need to stick to a certain filename format, so it’s not ideal, but it’s an extra level of protection for files, and it requires very little extra effort for the client to use it. Here’s the .htaccess file text we ended up with:

# Don't allow directory browsing
Options All -Indexes

# These next two lines will already exist in your .htaccess file
RewriteEngine On
RewriteBase /
# This line checks for the pattern in the filename
RewriteCond %{REQUEST_FILENAME} ^.*-internal.pdf$
# This line checks for the logged-in user's WordPress cookie
RewriteCond %{HTTP_COOKIE} !^.*wordpress_logged_in.*$ [NC]
# This line redirects the user if the conditions aren't met
RewriteRule . - [R=403,L]

We decided that only PDFs needed to be protected, and that any file that needed to be secure would have “-internal” at the end of the filename; that’s the “^.*-internal.pdf$” pattern. The .htaccess file sits on the server at wp-content/uploads/.htaccess, and as long as the client remembers to put “-internal.pdf” at the end of the filename before upload, those files can’t be downloaded unless the website user is logged in to WordPress. If the user isn’t logged in, they’re redirected to a friendly error page.