Disabling hotlinking/direct-linking via .htaccess

Started by chalky, April 08, 2023, 10:23:25

Previous topic - Next topic

chalky

After reading Derron's post in another thread (I forget which one) about file security on websites, I decided - as I have been doing exactly what he said not to for years - to review my configuration so that anything downloadable was done so via a script rather than a direct link. I therefore wrote a PHP script which downloads files and updated all the download links on my website to use it. So far so good. However, I realised that I could still download the file(s) via a direct link, so bought a book on .htaccess configuration ('htaccess made easy') and attempted to set up my site so that hotlinking/direct-linking was blocked.

To begin with, I added:

<IfModule mod_rewrite.c>
    RewriteEngine On
</IfModule>

<Files .htaccess>
    Order Allow,Deny
    Deny From All
</Files>

Followed by:

Options -Indexes
This was a positive start - as all attempts to access a directory via my broswer resulted in a 403.

However, if I included a file name (e.g. domain/directory/file.png) in the URL the specified file would still display in the browser window - so I added (substituting my own domain name) the following:

<IfModule mod_rewrite.c>
    RewriteCond %{HTTP_REFERER} !^$
    RewriteCond %{HTTP_REFERER} !^http(s)?://(www\.)?mywebsite.co.uk [NC]
    RewriteRule \.(bmp|gif|jpg|jpeg|pdf|png)$ - [NC,F,L]
</IfModule>

But this did not work as I could still get files to display in the browser if I typed a direct link to them.

So I tried adding:

<FilesMatch "\.(bmp|gif|jpg|jpeg|pdf|png)$">
    Order Allow,Deny
    Deny From All
</FilesMatch>

This DID work (any attempt to link directly resulted in a 403) - but now the images were being blocked from my own domain as well, and no images were therefore being displayed on my website.

Having searched on the internet, I read somewhere that the 'Allow From' clause now accepts domain names rather than IP, so I changed my FilesMatch definition to:

<FilesMatch "\.(bmp|gif|jpg|jpeg|pdf|png)$">
    Order Deny,Allow
    Deny From All
    Allow From mywebsite.co.uk
</FilesMatch>

Unfortunately this made no difference and files were still being blocked from my domain.

The need for me to get this working has increased recently as I have gained permission from another site owner to use their images on my site - but on the strict condition that I disallow hotlinking/direct-linking to them.

Despite reading the book's chapter on security several times over, I cannot work out what I have done wrong. Are there any .htaccess gurus on here who can help?

Qube

This any use for you?

RewriteCond %{HTTP_REFERER} !^$
RewriteCond %{HTTP_REFERER} !^http://(www\.)?mywebsite.co.uk/.*$ [NC]
RewriteRule \.(png|jpg|gif)$ mywebsite.co.uk/images/no-linking-please.png[R=302,L]
Mac Studio M1 Max ( 10 core CPU - 24 core GPU ), 32GB LPDDR5, 512GB SSD,
Beelink SER7 Mini Gaming PC, Ryzen 7 7840HS 8-Core 16-Thread 5.1GHz Processor, 32G DDR5 RAM 1T PCIe 4.0 SSD
ASUS PG27AQDM 27" OLED 240hz monitor

Until the next time.

Derron

Mine looks a bit different
RewriteEngine on
RewriteCond %{HTTP_REFERER} !^$
RewriteCond %{HTTP_REFERER} !^https?://(www\.)?gamezworld\.de(/.*)?$ [NC]
RewriteCond %{HTTP_REFERER} !^https?://(www\.)?gamejoker\.de(/.*)?$ [NC]
RewriteRule \.(gif|jpg|GIF|JPG)$ https://www.gamezworld.de/grafiken/hotlinking.png [R,L]

it cares for httpS (optional s) too


bye
Ron

chalky

Thank you both.

I tried Qube's RewriteRule suggestion, followed by Derron's - but after each of them I could still display images in the browser by direct-linking them.

Just in case,  I also checked with IONOS that module mod_rewrite is already active by default (which it is).

I am really confused now as this clearly should work! :(

chalky

I'm still flummoxed on this...

To summarise what I'm attempting to achieve, I have a root directory:

"mydomain.co.uk"
This contains 2 subdirectories:

"images/"
"info/"

The latter also has a subdirectory:

"images/" (i.e. "mydomain.co.uk/info/images/")
At the moment, what I have results in a 403 if the following is attempted via a browser (due to Options -Indexes):

"mydomain.co.uk/info/images" (as does "mydomain.co.uk/info" and "mydomain.co.uk/images"
However, I want to prevent someone displaying individual files from any directory/subdirectory by (for example) typing the following into their browser:

"mydomain.co.uk/info/images/myimage.png"
But the following does not work (nor do Qube/Derron's suggested alternatives) :

RewriteCond %{HTTP_REFERER} !^$
RewriteCond %{HTTP_REFERER} !^http(s)?://(www\.)?mydomain.co.uk [NC]
RewriteRule \.(bmp|gif|jpg|jpeg|pdf|png)$ - [NC,F,L]

Am I being a complete numpty and missing something which should be obvious?


Derron

What happens if you use my .htaccess and place it right in your "image" folder ?
(of course you need to adjust the domain stuff ...)

If that works, next thing you could do is to add a new .htaccess file to your root folder (so where your "index.php" is located):
RewriteBase /your_root_path/
RewriteOptions InheritDown

It might be that some setting in your apache (httpd.conf - maybe not accessible for your in your hosting setup) is set to use the "directory" limitation, which makes .htaccess only work for the folder in which it is stored.


bye
Ron

chalky

Hi Derron,

Thanks for taking the time to respond.

I read on the IONOS help pages that "RewriteBase /" had to be included, so added it - but it made no difference. I also double-checked that the domain is pointing to the directory in which I'm placing the .htaccess file - which it is.

This is what I now have in my .htaccess file:

# Block Access to .htaccess
<Files .htaccess>
  Order Allow,Deny
  Deny From All
</Files>

# Disable Index Views
Options -Indexes

# Enable Mod_Rewrite
RewriteEngine On
RewriteBase /

# Activate HTTPS
RewriteCond %{Server_Port} !=443
RewriteRule ^(.*)$ https://ndgmusic.co.uk/$1 [R=301,L]

# Block Hotlink Requests
RewriteCond %{HTTP_REFERER} !^$
RewriteCond %{HTTP_REFERER} !^https?://(www\.)?ndgmusic.co.uk/.*$ [NC] [OR]
RewriteRule \.(bmp|gif|jpg|jpeg|pdf|png|zip)$ - [R,L]

ErrorDocument 400 default
ErrorDocument 401 default
ErrorDocument 403 default
ErrorDocument 404 default
ErrorDocument 500 default

Can you see anything wrong with it?

The redirect to https:// is working fine, but - no matter which directory I put a 'block hotlink' .htaccess file - I can still display images in my browser by typing their direct URL. I have even put .png and .jpg files in the root directory as a test (to negate nested directories being the issue) - and they too display in the browser.

I think I'm going to have to accept that I cannot do this - as nothing I try works. If my file is ok - could this be something to do with the IONOS Apache configuration (which unfortunately I do not have access to)?

Derron

Two things:
First: your script looks OK.

Second: when directly opening your image (using domain.tld/yourimg.png) then you will send an empty "referer". Your .htaccess allows them to load the file.

For "images" this is OK, as it avoids that others "<img src...>" your image into their website (in that case they eg get an "hotlink.jpg" served or so.

Think this articles covers it too:
https://alistapart.com/article/hotlinking/


To secure your "downloads" you might disable the first referer entry (the "blank") one.
You are also able to serve the files through a php script - so you can eg increase a download counter or ... block access when referer is not "your domain" or if the user has no cookie set, is not logged in .. has already downloaded 10 things this hour ...


bye
Ron

chalky

Quote from: Derron on April 10, 2023, 20:07:49when directly opening your image (using domain.tld/yourimg.png) then you will send an empty "referer". Your .htaccess allows them to load the file.
Quote from: Derron on April 10, 2023, 20:07:49To secure your "downloads" you might disable the first referer entry (the "blank") one.

Derron - you're a flipping marvel - removing the 'blank referrer' RewriteCond fixed the issue (though I am cursing myself for not realising the 'logic' behind 'if not empty', particularly having spent a long time trying to understand what I'd done wrong)!

The linked article also proved an interesting read - even if the example contained within it (meant to prohibit the image from being viewed) didn't work!

Thanks for all your help - I owe you a [very] large drink... ;D

Amon

Can anyone show me step by step how to set this up for my domain please? I'd like to do the same because I noticed that people are hotlinking my downloads and I'd like to stop that.