.htaccess - Check Referer Matches Host Without Hard Coding?

4.6k views Asked by At

I would like to do the typical thing where you make sure a referrer header matches your host, using htaccess. However I would like to do this without hard coding the domain name, so the htaccess code can easily be reused across many many sites.

I know this is the typical way to do it. Imagine I have one main server at WWW.example.com, and an image server at IMG.example.com:

RewriteCond %{HTTP_HOST} !^(www\.)
RewriteCond %{HTTP_REFERER} !^$
RewriteCond %{HTTP_REFERER} !https?://(([^\.]+)\.)?example\.com/    [NC]
RewriteRule DO SOMETHING HERE [L]

But how can I somehow do this without hardcoding 'example.com' into the Rewrite condition? I was thinking of trying to use %{HTTP_HOST} inside the referrer rewrite condition somehow, but I'm not sure how to match just the last/domain part and bring it inside. Maybe there is some way I can match the host, put the results into a variable, then be able to use that variable on the next RewriteCond line?

I'm a little lost. Thanks for any help!

1

There are 1 answers

3
DerDu On BEST ANSWER

Referrer Checking with .htaccess

Referrer checking is a mechanism to restrict the way web resources are used. Specifically, you can use this technique to insist that files only be viewed from a specific page or site (or, rather, only viewed if the browser says that it’s viewing the file on your site, truthfully or otherwise).

Normally you would set up a referrer check in an htaccess file like this:

RewriteEngine On
RewriteCond %{HTTP_REFERER} !^http://www.example.com/.*
RewriteRule .*\.pdf - [NC,F]

The first line turns on rewriting, the second checks to see if the “REFERER” header (yes, spelled that way) does not start with “http://www.example.com/”, and the third line marks all files ending in “.pdf” as forbidden.

That’s nifty and useful and all, but it’s site-specific. You have to change the code to match your domain, and sometimes the exact same code needs to be applied across multiple domains. It’d be nice to check to see if the REFERER header contains the same domain name as the HOST header.

Ideally, you could do something like this:

This doesn't work

RewriteCond %{HTTP_REFERER} !^http://%{HTTP_HOST}/.*

Sadly, you’re not allowed to compare one server variable against another in a RewriteCond. We can work around this restriction by putting both variables on the same side of the condition, and then comparing the result against itself. Like so:

This one works -- feel free to copy it onto your own site.

RewriteEngine On
RewriteCond %{HTTP_HOST}@@%{HTTP_REFERER} !^([^@]*)@@https?://\1/.*
RewriteRule .*\.pdf [NC,F]

This may be a bit confusing at first, so let’s reason through it. On the left-hand side of the comparison, we have %{HTTP_HOST}@@%{HTTP_REFERER}. So for example, that would result in a string like this: tltech.com@@http://tltech.com/info. On the right-hand side of the validation rule, “^([^@]*)” means “remember everything before the first @ sign. Then we skip over the @@http:// (or optionally @@https://). Then make sure that the next bit matches the host name we remembered at the start. Then we make sure that’s followed by a / sign. And that’s it.

Essentially, this rule checks to see if the host name in the HTTP_REFERER field is exactly the same as the hostname in HTTP_HOST. And if that’s not the case, then the last line tells apache to block the specified file type.

Cool, eh? The best part is that you can cut-and-paste the code into any host without having to change anything about it. Just make sure that last line matches the file type or name that you want to restrict, and you’re golden.


Source: http://tltech.com/info/referrer-htaccess/