views:

135

answers:

4

I need to confirm something before I go accuse someone of ... well I'd rather not say.

The problem:

We allow users to upload images and embed them within text on our site. In the past we allowed users to hotlink to our images as well, but due to server load we unfortunately had to stop this.

Current "solution":

The method the programmer used to solve our "too many connections" issue was to rename the file that receives and processes image requests (image_request.php) to image_request2.php, and replace the contents of the original with

<?php
header("HTTP/1.1 500 Internal Server Error") ;
?>

Obviously this has caused all images with their src attribute pointing to the original image_request.php to be broken, and is also the wrong code to be sending in this case.

Proposed solution:

I feel a more elegant solution would be:

In .htaccess

  1. If the request is for image_request.php
  2. Check referrer
  3. If referrer is not our site, send the appropriate header
  4. If referrer is our site, proceed to image_request.php and process image request

What I would like to know is:

Compared to simply returning a 500 for each request to image_request.php:

How much more load would be incurred if we were to use my proposed alternative solution outlined above?

Is there a better way to do this?

Our main concern is that the site stays up. I am not willing to agree that breaking all internally linked images is the best / only way to solve this. I refuse to tell our users that because of something WE changed they must now manually change the embed code in all their previously uploaded content.

+1  A: 

Using ModRwrite will probably give you less load than running a PHP script. I think your solution would be lighter.

Make sure that you only block access in step 3 if the referer header is not empty. Some browsers and firewalls block the referer header completely and you wouldn't want to block those.

Emil Vikström
Very difficult for me to decide on the best answer for this question. Accepted this one because it was the first to address the load difference issue. Every answer to this question has been extremely helpful, hence my difficulty in choosing the "best". Thank you all!
Michael Robinson
+1  A: 

I assume you store image paths in database with ids of images, right? And then you query database for image path giving it image id.

I suggest you install MemCached to the server and do caching of user requests. It's easy to do in PHP. After that you will see server load and decide if you should stop this hotlinking thing at all.

FractalizeR
Great idea about memcached, unfortunately I'm a one man dev team and don't have time to install / make required code changes right now. I would LOVE to have hotlinking enabled and watermark hotlinked images, but we're running with a skeleton crew with rickety servers and just need something that will allow our site to display our images, and prevent (for now) other sites from hotlinking to us.
Michael Robinson
Added another answer about preventing hot-linking with mod_rewrite.
FractalizeR
+1  A: 

Your increased load is equal to that of a string comparison in PHP (zilch).

The obfuscation solution doesn't even solve the problem to begin with, as it doesn't stop future hotlinking from happening. If you do check the referrer header, make absolutely certain that all major mainstream browsers will set the header as you expect. It's an optional header, and the behavior might vary from browser to browser for images embedded in an HTML document.

You likely have sessions enabled for all requests (whether they're authenticated or not) -- as a backup plan, you can also rename your session cookie name to something obscure (edit: obscurity here actually doesn't matter as long as the cookie is set for your host only (and it is)) and check that a cookie by that name is set in image_request.php (no cookie set would indicate that it's a first-request to your site). Only use that as a fallback or redundancy check. It's worse than checking the referrer.

If you were generating the IMG HTML on the fly from markdown or something else, you could use a private key hash strategy with a short-live expire time attached to the query string. Completely air tight, but it seems way over the top for what you're doing.

Also, there is no "appropriate header" for lying to a client about the availability of a resource ;) Just send a 404.

Aaron
If a resource is available but the server still refuses to serve it, it should send 403 (forbidden).
Tgr
Right you are, thanks.
Aaron
+1  A: 

Ok, then you can use mod_rewrite capability of Apache to prevent hot-linking:

http://www.easymodrewrite.com/example-hotlinking

FractalizeR
This is a great link, thanks. I have sent it to the developer who is working on a proper solution now.
Michael Robinson
Welcome. I home you at least upvote my suggestion ;))
FractalizeR