Protect WordPress Media Files
This is an experimental technique that I am playing with. It’s the simplest possible way that I could think of to protect all files in the WordPress Media Library using only Apache/.htaccess. I’ve been testing the code on an image-heavy site and so far there are no issues. So I want to put the code out there for others to test and hopefully provide feedback if anything less than perfect. It’s a super simple method that prevents media files from being accessed from anywhere other than the site at which they are hosted.
What it Does
This technique adds a slice of code to your main .htaccess
file. The code checks if the URI request is for any file inside of the WP Media Library, specifically any file located in the /wp-content/uploads/
directory. If the request is for a media file, the code then checks if the referrer matches your site URL. If it doesn’t match, the image request is from some other site, and thus will be blocked. This technique works because the site hosting the images always is the referrer for image requests.
The Code
Here is the .htaccess
code to protect WP media files. Make sure to read the Pros and Cons before using this technique.
# Protect WP Media Files
# https://m0n.co/protect-media-files
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{REQUEST_URI} /wp-content/uploads/ [NC]
RewriteCond %{HTTP_REFERER} !^https://example.com [NC]
RewriteRule .* - [F,L]
</IfModule>
Add that to your site’s main .htaccess file, change example.com
to match your site, and done. You can (and should) test the technique by visiting pages that display your media files. Also try requesting the media files directly. Also you can test hotlinking of your images by using a free online hotlink checker. Test well and please report any bugs, issues, etc.
How it Works
For those interested in how the code works, here is a line-by-line breakdown:
- Open the
<IfModule>
container ifmod_rewrite
exists - Make sure the rewrite engine is enabled (see note)
- Check if the requested URI is for anything in the WP Media Library
- Check if the referrer matches the site URL
- If both of the previous conditions are true, the request is denied via 403 “Forbidden” response
- Close the
<IfModule>
container
So the technique is very simple and lightweight. Again, remember to change the example.com
with the actual URL of the site. Then test well.
RewriteEngine On
rule declared in your .htaccess
file. Apache simply ignores once the Rewrite Engine is enabled.Pros & Cons
There are some pros and cons to techniques like this. First the Pros:
- Pro — Protects against hotlinking
- Pro — Prevents direct image access (i.e., no referrer)
- Pro — Helps to ensure images are display only on your site
- Pro — Super simple, lightweight and fast
And the Cons:
- Con — Prevents images from appearing in image search results
- Con — Prevents direct image access (i.e., no referrer)
- Con — Experimental, not well tested (as of 2021/11/21)
- Con — It’s possible for bad actors to fake/spoof the referrer
So it’s a limited use-case scenario, where you want to retain as much control and protection for your images as possible. Notice that some items are on both pro and con lists. This is because whether pro or con depends on your goals, strategy, and so forth. For example, Andy may like to see his images appear in image-search results. While April on the other hand, would rather not.
Also keep in mind that this technique is not 100% guarantee of anything. It is just as strong as other anti-hotlink and image-protect techniques, but could be bypassed by anyone with the ability to spoof a referrer. Spoofing a referrer is one of the oldest tricks in the book, however most requests don’t bother spoofing anything. So the technique generally should be effective.
Related Infos
- How to Setup Secure Media Uploads
- Secure uploads, upgrade and other directories with .htaccess
- Block bad bots via Referrer
- Block bad bots via Request URI
- Stupid .htaccess tricks
7 responses to “Protect WordPress Media Files”
Hi Jeff,
Thank you for this. I like the simplicity of your solution. I’m wondering about something. There’s a WordPress security plugin I like to use, which has a ‘Prevent Image Hotlinking’ feature. Their solution also writes to the .htaccess file and produces a slightly longer piece of code that looks like this:
I’m wondering how this code works differently from yours and if it would have different pros and cons.
Thanks again,
Dave
Hi Jeff, me again,
So I decided to use the hotlink checker you referenced to test the security plugin’s code and your code on a live site.
Turns out the security plugin’s code doesn’t actually stop hotlinking from happening and your code does. So I guess that answers my question about the difference between the two ; )
At the same time, I’m assuming the developers of the security plugin did test their solution and found it satisfactory, so I’m still curious about your thoughts too…
Hey Dave, great to hear from you. I hope you are doing well.
Not sure what’s up with your security plugin’s .htaccess rules. Looks like the logic is a bit off though. Would need to do some testing to be sure. Best advice would be to ask the plugin providers why it’s not working, they should be able to resolve any logical inconsistencies.
I used it, great:) Something for protecting themes folder and files?
Wasn’t sure what you were specifically referring to as to protecting the “themes” folders, but the general RewriteCond for protecting the media within them should also work there – unless you have another .htaccess file within that/those folder(s) that are “short-circuiting” your upper-level .htaccess file.
If you are talking about keeping web-access to those files limited to within your site’s resources (IE: called by your web page(s), for instance), You could try:
But I would test it first! If any of your themes use JavaScript to “Request” any other resources within your “theme’s” folder, this may not work as well – as Javascripted “Request events” often do not send a “referrer”-header!
This bit of directives is to only allow access to the contents of the “themes” folder – if “referred to by” a request from within your webpage(s) on your site.
IF you are confident that NONE of your themes ever need to have “web-access” (IE: via “HREF” or any “SRC” values) to any of the PHP files in them (which NONE of them should, normally),
You could try this one:
Again, TEST them one-at-a-time first, before committing them to your live site(s).
I actually use several sets of Rewrites to further protect my media and the folders in general. THIS kind became necessary because of other nefarious attempts of attacks too. First off, I try to reduce how many lines in the .htaccess I use to get the job done:
( The last RewriteCond should work well, even if you didn’t set the MIME-type restrictions within WordPress – but it is recommended that you use the WordPress feature at a minimum. )
As I always caution:
TEST everything, individually, before applying it to your “live site(s)”.
– J.S.Smith
Nice hack, Jeff! I used it and it works nicely. Thanks for sharing