Page 1 of 1

Protecting images by putting them outside the root

Posted: Tue Mar 22, 2011 5:31 pm
by bobthebuilder
Hello

I would be very grateful if anyone could answer this query, I imagine it's a common issue.

I am developing a site where customers will upload images having previously registered and logged-in. I imagined these would be stored (in thumbnail form) outside the root so one user could not see the images of another user.

But what I want to happen is for a php page to list all the images in a user's directory and then show them as a gallery so the user can select them etc.

Obviously this doesn't work using code of the form

Code: Select all

echo"<img src=\"" . ALL_FRAME_TEMPLATES . "$the_file \"" . "align=\"left\" /></a>";  
since the $the_file image in the directory ALL_FRAME_TEMPLATES is outside the root. So how can I securely display images that are outside of the root directory? The best answer I can think of is getting a php script to copy the images into a randomly named directory within the root, and then use similar code to that shown above, removing the directory when the user logs out. This doesn't sound too smart though!

What is the clever way to do this? Thanks in advance.

Re: Protecting images by putting them outside the root

Posted: Wed Mar 23, 2011 10:22 am
by Bind
You can use PHP GD

example:

Code: Select all

<?php
header("Content-type: image/jpeg");
if($im=imagecreatefromjpeg('/www/host/user/protected_images/user01-category01-image01.jpg'))
   {
      if(imagejpeg($im))
         {
            imagedestroy($im);
         }
   }
?>
it is very important to destroy each image in server memory after its creation and output since GD can be very resource intensive, else you may get memory allocation errors at runtime.

You may also be able to stream them directly using fpassthru(), readfile(), or fopen() and fgets().

Re: Protecting images by putting them outside the root

Posted: Wed Mar 23, 2011 2:34 pm
by bobthebuilder
Thanks for the input Bind. I guess your approach works by loading the image into a new web-page. (I haven't tried it yet!)

Possibly wouldn't solve the problem of me wanting to click on images to enable me to process them with other PHP files, like I would be able to if they were in the root.

I wondered if one approach is to generate a random string when the user registers, and use this as the directory name in the root so I can then link to the images directly. I would extract this ID when the user logs in and store it in a session variable. For one user to view another user's images he would have to guess the random string denoting the directory name.

Re: Protecting images by putting them outside the root

Posted: Wed Mar 23, 2011 4:32 pm
by AbraCadaver
Assuming you're using sessions for authenticated users, I would do the following (illustrative only):

Code: Select all

//gallery.php
$images = glob('/somewhere/out/of/docroot/'.$_SESSION['username'].'/*.jpg');
foreach($images as $image) {
   echo '<img src="image.php?image='.basename($image).'">';
}

Code: Select all

//image.php
if(file_exists('/somewhere/out/of/docroot/'.$_SESSION['username'].'/'.$_GET['image'])) {
   header('Content-type: image/jpeg');
   readfile('/somewhere/out/of/docroot/'.$_SESSION['username'].'/'.$_GET['image']);
}

Re: Protecting images by putting them outside the root

Posted: Wed Mar 23, 2011 6:06 pm
by bobthebuilder
Abra, thanks. That looks like the kind of approach I initially thought wouldn't work because it is essentially using an <img tag to reference an image outside of the root. I shall give it a go though, as maybe I've got the wrong end of the stick regarding getting images outside the root.

Re: Protecting images by putting them outside the root

Posted: Wed Mar 23, 2011 6:37 pm
by Jonah Bron
@bobthebuilder: that's what the second part is for. It accesses the images outside the root. You'll see that the <img> src points to image.php.

Re: Protecting images by putting them outside the root

Posted: Fri Mar 25, 2011 3:34 am
by bobthebuilder
Thanks gents. Works a treat!

Re: Protecting images by putting them outside the root

Posted: Fri Mar 25, 2011 11:52 pm
by Bind
another issue with image streaming is that it bypasses htaccess hotlink protection, so you may want to code in your own hotlink protection if you want to prevent others from using your service as a 3rd party image hosting service sucking up your bandwidth by displaying your images from another website.

Code: Select all

<?php
if($_SERVER['HTTP_REFERER'])
   {
      if(!strpos($_SERVER['HTTP_REFERER'],$_SERVER['HTTP_HOST']))
         {
            exit('hotlinking is disabled);
         }
   }
?>
NOTE: even though your application may require login to access the images, it still may be possible to login with curl then access the image.php for hotlink display during the same script exection if your login has no automation protection,.

Re: Protecting images by putting them outside the root

Posted: Sat Mar 26, 2011 9:06 am
by bobthebuilder
Thank's Bind, you've got me worried now... Are you suggesting that I might need a recaptcha for example on my login script? I have one with the registration form and thought that would be enough of a deterant.

Re: Protecting images by putting them outside the root

Posted: Sat Mar 26, 2011 9:58 am
by greyhoundcode
Bind wrote:

Code: Select all

<?php
if($_SERVER['HTTP_REFERER'])
   {
      if(!strpos($_SERVER['HTTP_REFERER'],$_SERVER['HTTP_HOST']))
         {
            exit('hotlinking is disabled);
         }
   }
?>
This codes relies on the assumption that HTTP_REFERER will be set. If hotlinking is likely to be a problem then perhaps an approach that doesn't rely on this header being set would be preferable.
PHP Manual wrote:Not all user agents will set this, and some provide the ability to modify HTTP_REFERER as a feature. In short, it cannot really be trusted.

Re: Protecting images by putting them outside the root

Posted: Tue Mar 29, 2011 11:01 am
by Bind
yes captcha would certainly take care of 100% of any abuse, but some might find forced captcha on logins to be prohibatively cumbersome and time consuming to enter, which is why I prefer the HTTP_REFERER method that replicates Apache's HTACCESS's hotlink protection. But hey its your decission - if your members dont mind captcha, use it.

You see, if one of your members tries using your site and stops sending the HTTP_REFERER header, thats fine and it wont really affect your bandwith if they use it on a personal level. Can't really do anything about it anyways (except for captcha).

However, if its a high volume public site, thats a big difference, and since the majority of casual surfers and visitors send the HTTP_REFERER, then it will stop most of the abuse with a very small resource consuption footprint. In fact they wont even hotlink it since the majority of their visitors wont be able to see it - would make them look unprofessional to their members linking an image few can look at without blocking the referer sends.

@greyhoundcode - we are not trusting it - we are trusting that its merely present for the majority of visitors who do send headers - it's values are irrelevent. Visitors who have referer blocked we really cant do anything about, much like HTACCESS referer-based hotlink protection.