A LIST Apart: For People Who Make Websites

No. 185

Discuss: Smarter Image Hotlinking Prevention

Pages

« First  <  7 8 9

81 Thanks, Thomas Scott!

Bless you. This fixes my situation nicely.

(I too am on FF 0.9.2, and I get the “end result” just fine.)

posted at 06:17 pm on August 4, 2004 by Vkaryl

82 A (Refined?) Version

Hi, folks!

I enjoyed the article and am impressed at the amount of collaborative critique and revision has happenned since the first version!

I have revised and tested scenarios surrounding the ideas in this article (and subsequent comments) and have a version which may be of interest to someone.

Without further ado:

- – - A (Refined?) Version – - –

I have removed, from the .htaccess example in the article, allowances for google. These may be added in again easily. I simply did not need them in my case. I have also incorporated an allowance for referrer filtering software that obfuscates the referrer string (the second RewriteCond line, a variation of an earlier post except without the allowance for newsreaders). Naturally, change example.com in the fourth RewriteCond line to your own domain.

Here is the .htaccess snippet:

  1. BEGIN .HTACCESS DIRECTIVES

  1. Set per-dir options

Options +FollowSymLinks
RewriteEngine On
RewriteBase /

  1. Hotlink protection
  2. This stops robot indexing, offsite cacheing, and embedding of our images in other webpages by
  3. throwing a (403) Forbidden status (takes care of most robots) followed by a text/html MIME-type
  4. as the explanation/error document (takes care of requests expecting an image MIME-type, such as
  5. in the case of an embedding request from another website)
  6. The explanation produced is a normal HTML document which displays:
  7. 1. a copyright notice
  8. 2. the originally requested image (embedded in the response page)
  9. 3. a link to our homepage
  10. This approach still allows linking to images, as in the case of pointing to an image in a gallery
  11. Exceptions: (causes a pass-thru)
  12. Referrer is invalid or empty (takes care of direct client requests and some referrer filters)
  1. Requests from our own domain (so we can embed the images in our own pages)

RewriteCond %{REQUEST_URI} \.(jp(e?)g|gif|png)$ [NC]
RewriteCond %{HTTP_REFERER} ^http(s?) [NC]
RewriteCond %{HTTP_REFERER} !^$
RewriteCond %{HTTP_REFERER} !^http(s)?://(www\.)?example\.com [NC]

RewriteRule .+\..{3,4}$ /showpic.php [T=application/x-httpd-php,L]

  1. END .HTACCESS DIRECTIVES

Place this in your document root directory’s .htaccess file and your whole site is covered.

Now, for the interesting part. You may have noticed that we did not put a query string at the end of the RewriteRule. No, it is not a bug, it is really a feature! No, I’m not crazy (at least nobody has ben able to prove it, yet!)

Apache is wonderful in how much information is made available to you via environment variables — without you doing anything special! You need not rely on userspace GET variables that can be easily tampered with. Apache remembers the original location of the image requested in a special environment variable called REDIRECT_URI. The wonderful thing about this is that Apache has already stripped out any goofy XSS (Cross-Site Scripting) problems by validating the URI syntax internally. Wasn’t that a nice daemon? Good daemon.

So now that we know our original image request data is nice and safe in Apache environment variables, we move to the revised PHP code:

  1. BEGIN PHP SCRIPT

<?php //showpic.php

# this script is used in conjunction with Apache httpd and mod_rewrite to limit hotlinking # of images to legitimate requests and allow direct links to images, which generate # an html page that displays the image with appropriate credit and link to our homepage. IF (! (ARRAY_KEY_EXISTS(‘REDIRECT_URL’, $_SERVER) && ($_ = $_SERVER[‘DOCUMENT_ROOT’] . ‘/’ . $_SERVER[‘REDIRECT_URL’]) && (@ FILE_EXISTS($_)))){ HTTP/1.x 404 Not Found”">HEADER; HEADER; // hide fact PHP is sending the headers HEADER; // hide fact PHP is always ready to send content back EXIT; } HTTP/1.x 403 Forbidden”">HEADER; HEADER; GMT”">HEADER; HEADER; FALSE">HEADER; HEADER; HEADER; HEADER; ?> <!DOCTYPE html PUBLIC “-//W3C//DTD HTML 4.01//EN” “http://www.w3.org/TR/html4/strict.dtd”> <html> <head> <title>Example.com : Direct Image Request</title> <meta http-equiv=“Content-Type” content=“text/html; charset=iso-8859-1”> <style> <!— body{ text-align: center; background: #96f; } body div{ text-align: center; background: #fff; padding: 5px; } —> </style> </head> <body> <h1>Image file: <?php ECHO ($_ = REDIRECT_URL’]">BASENAME) ?></h1> <div> <?php ECHO $_ ?> </div> Image © <?php $_ = GETDATE; ECHO $_[‘year’] ?> Example.com. All rights reserved. Please, visit our website at [url=“http://<?php ECHO ($_ = $_SERVER[‘SERVER_NAME’]) ?>/”]<?php ECHO $_ ?>[/url]. </body> </html>

  1. END PHP SCRIPT

First, we need not mess with GET variables anymore. Second, as long as you put showpic.php in the document root, this will cover your whole site, since the full image path is constructed at the top of the script. Third, robots will not be thrown, because we send a correct 403 Forbidden response.

I used a (sly?) trick with the 403 thing. The HTML following it is actually an explanatory error document, but the user will never know it unless they check the headers! So long as the document is large enough, this should be displayed in place of even MSIE’s error documents! This error document, being of the text/html MIME-type, will still break embedding of your images into other sites, regardless of whether their server ignores the 403.

The script also updates the copyright date to the current year automatically and refers to $_SERVER[‘SERVER_NAME’] to get your site name for the link to your homepage and the link text. In the interest of accessibility, the image ALT text provides a generic explaination as to why the image has no real description.

Obviously, you would want to adjust the CSS and copyright notice to your own needs and attributions.

Hopefully, this provides a robust and elegant solution that someone will find useful!

Cheers!

BTW: My site is not up yet, but it will be sometime in September. Come visit then, won’t you? ;)

posted at 06:20 am on August 5, 2004 by Ray McCord

83 One more thing...

Though this may be obvious to some, this site word-wrapped the code in my prior post, so be careful with the comments starting with ‘#’ and all of the lines in the .htaccess example!

Cheers!

posted at 06:36 am on August 5, 2004 by Ray McCord

84 One more thing... (part deux)

I made a typo in the explanation of environment variables:

“Apache remembers the original location of the image requested in a special environment variable called REDIRECT_URI.”

REDIRECT_URI” should be “REDIRECT_URL”.

Thankfully, the typo was not in the all-important code itself.

Carry on. ;)

posted at 07:35 am on August 5, 2004 by Ray McCord

85 Fire !

How about guys with firewalls installed ???

posted at 09:41 pm on August 19, 2004 by Omega Replica

86 Mozilla 1.7.3

The “Nope, guess not” page does have an image, didn“t work i guess..

posted at 03:38 am on September 24, 2004 by Kazze

87 Code cleanup

While getting some help from Webmaster World regarding my .htaccess file, I inadvertantly got a bit of information regarding tightening up the hotlink prevention code. Some of you may be interested.

http://www.webmasterworld.com/forum92/2101.htm

posted at 09:33 am on September 24, 2004 by pat

88 Great

Just loved it!

posted at 01:47 pm on October 29, 2004 by Alicia

89 doing it all with rewrite

is it possible to redirect from somefile.jpg to somefile.jpg.html just using mod rewrite?

so if someone comes in from google images they are sent to the html file without writing a rule for each file.

Paul

posted at 03:43 pm on November 10, 2004 by Paul

90 I can still see the images

Where it states that the images should fail to load I can still see it, same kitty cat but without any text on both “blocked” ones.
IE 6 is the browser and it appears the script doesn’t work very well.
I put an HTA access file on my site server and it works for some and not for others, more often than not it doesn’t work.

posted at 08:08 pm on November 19, 2004 by Legal Eagle

Pages

« First  <  7 8 9

Discussion Closed

New comments are not being accepted, but you are welcome to explore what people said before we closed the door.

Got something to say?

Discuss this article. We reserve the right to delete flames, trolls, and wood nymphs.

Create a new account or sign in below if you’d like to leave a comment.

Remember me

Forgot your password?

Subscribe to this article's comments: RSS (what’s this?)