Page 1 of 2

Preventing direct image link?

Posted: Thu Nov 25, 2004 8:33 am
by bradles
Hi All,

I have an image gallery that my client's log into to view their pictures.
How does one go about preventing a user just simply accessing the images from the browser like:
http://www.domain.com/clients/smith/images/001.jpg

I have the folder set up so you cannot get a directory listing but it doesn't stop them accessing the image. If someone was able to guess the folder path and image names they could access images.

Brad.

Posted: Thu Nov 25, 2004 8:35 am
by peni
you can controll the access by checking referers, afaik.

Posted: Thu Nov 25, 2004 8:40 am
by hedge
store the folders outside of the webserver root.

Posted: Thu Nov 25, 2004 8:41 am
by bradles
Hedge,

If that works I'm going to call you a genius!!! :)

Brad

Posted: Thu Nov 25, 2004 8:54 am
by bradles
Problem is now I can't get my script to pull them in.

I checked the source code for one of the images i'm trying to bring in with my script on the server.
<img src="../clients/smith/images/001.jpg"

But no image. What am I missing?

Brad.

Posted: Thu Nov 25, 2004 10:13 am
by phpScott
is your directory structure such

/clients
/smith
/images
/jones
/images
/webRoot
/this is where you page that includes the images sits.

??

Posted: Thu Nov 25, 2004 11:29 am
by hedge
bradles wrote:Problem is now I can't get my script to pull them in.

I checked the source code for one of the images i'm trying to bring in with my script on the server.
<img src="../clients/smith/images/001.jpg"

But no image. What am I missing?

Brad.
with my method, you need a helper script to go get the image. So for your example the html has to change like so

<img src="getpic.php?img=001.jpg">

Then the script would check security, send a header and then passthrough the file. If your site is already built this is not an easy method to implement.

What type of login system are you using? http_authentication, cookies/sessions etc.? Maybe you can do something creative with an .htaccess file?

Posted: Thu Nov 25, 2004 5:09 pm
by bradles
The site is nearly finished. I am using a fairly simple session login system and will probably need to tighten security of it at a later stage.

It would be nice to be able to do a something creative with a .htaccess if it makes it easier to access the images. I am just trying to make it as difficult as possible to access images straight from the web browser address.

Brad

Posted: Thu Nov 25, 2004 5:51 pm
by rehfeld
you could do this w/ htaccess and by checking referrers, but referrer headers arent 100% reliable. while you could use apache authentification, i think it would be easiest to just use your current login system, because thats what decides whether they should be able to see the pics. no need for a second system.



if you only want to show the images to those who are logged in, then do just that.

i would use the suggestion above, use a helper script

Code: Select all

&lt;?php



session_start();

// $_SESSION&#1111;'logged_in'] must evaluate to boolean true
if (empty($_SESSION&#1111;'logged_in'])) {
    exit;
}

if (!isSet($_GET&#1111;'pic'])) {
    exit;
}

$picture_dir = 'path/to/images/';
$picture_file = $picture_dir.$_GET&#1111;'pic'];

if ($picture_dir === dirname($picture_file)) { // security check, prevents them from doing this <span style='color:blue' title='I&#39;m naughty, are you naughty?'>smurf</span> getpic.php?pic=../../../../password_file
    if (is_readable($picture_file)) { // check if the file/pic exists
        // you will prob need to send a mime header as well here
        // output the image
    }
}



?&gt;

Posted: Sat Nov 27, 2004 6:57 am
by bradles
I went back to having my directory's live on the site eg., http://www.domain.com/clients/smith/images/001.JPG.
I applied a .htaccess password required in order to access the 'clients' folder. I thought I would be able to put a .htaccess on the 'clients' directory and have the php script still be able to pull the images into the script. Unfortunately when the client logs in they get the username password required for the .htaccess after they login.

I'm guessing there is a way I could have a script that inputs the username/pass for the .htaccess but I'd need to .htaccess password every client's folder with different user/pass's. That wouldn't be very efficient.

How do other people handle this situation where they want to limit access to a certain folder for a certain user?

Brad

Posted: Sat Nov 27, 2004 2:33 pm
by rehfeld
you could use the code i gave you, w 1 change

instead of having the picture_dir the same for all users



$picture_dir = "path/to/images/$username/";

Posted: Sat Nov 27, 2004 5:13 pm
by bradles
rehfeld wrote:you could use the code i gave you, w 1 change
instead of having the picture_dir the same for all users
$picture_dir = "path/to/images/$username/";
Rehfeld,

I'm trying your suggestion but I am having trouble with my understanding of how it works.

Code: Select all

<?
$picture_dir = 'clients/smith/images/';
$picture_file = $picture_dir.$_GET['350.jpg'];

if ($picture_dir === dirname($picture_file)) { // security check, prevents them from doing this s**t getpic.php?pic=../../../../password_file
    if (is_readable($picture_file)) { // check if the file/pic exists
        // you will prob need to send a mime header as well here
        // output the image
		
    }
}

//Below is my echo test to see what is being returned.
echo $picture_dir . "\n";
echo $picture_file;

?>
I get the following error:
Notice: Undefined index: 350.jpg in G:\ApacheServer\PHPTESTS\imagehelperscript.php on line 3
clients/smith/images/
clients/smith/images/
Brad

Posted: Sat Nov 27, 2004 6:22 pm
by rehfeld
the code wasnt meant to work, it was to point you in the right direction and you finish it.

i did have an error in my logic, its fixed in the code below, and its pretty much complete, you just need to tweek it to your needs.


Code: Select all

&lt;?php

session_start();

// im setting the following 2 sessions vars ONLY for this demo, 
// when the site is live you must remove them from this file and set them ONLY when the user logs in
$_SESSION&#1111;'logged_in'] = true;
$_SESSION&#1111;'username'] = 'bradles';


if (empty($_SESSION&#1111;'logged_in'])) {
    exit;
}

if (empty($_SESSION&#1111;'username'])) {
    exit;
}

if (!preg_match('/^(&#1111;A-Za-z0-9]+)$/', $_SESSION&#1111;'username'])) { // username must only contain letters and numbers
    exit;
}

if (!isSet($_GET&#1111;'pic'])) {
    exit;
}





$file_ext = end(explode('.', $_GET&#1111;'pic']));

$picture_dir = 'images/'.$_SESSION&#1111;'username'];
$picture_file = $picture_dir.'/'.$_GET&#1111;'pic'];


if ($picture_dir === dirname($picture_file)) {
    if (is_readable($picture_file)) {
        header('Content-Type: image/'.$file_ext);
        readfile($picture_file);
    }
}


?&gt;

heres how the file/folder structure should be

Code: Select all

doc root (directory)
        |---getpic.php
        |---images (directory)
                   |-----bradles  (directory)
                                   |----apple.jpg
                                   |----orange.gif
                   |-----username2  (directory)
                                   |----bannana.jpg
                                   |----pear.gif
then this is how to use the images

<img src="getpic.php?pic=apple.jpg">


so put getpic.php in yor docroot
in your doc root, make a folder named images
in the images folder, make a folder named bradles
in the bradles folder, place an image called apple.jpg

then goto the url:
yourwebsite.com/getpic.php?pic=apple.jpg

and you will see the image

Posted: Sat Nov 27, 2004 9:47 pm
by bradles
rehfeld,

Thanks for your help. You are certainly leading me in the right direction and I appreciate your help.
I have tweaked the code(below) for my login script.

Code: Select all

<?
session_start();

if (empty($_SESSION['logged_in']) || $_SESSION['logged_in'] != 'true') {
	exit;
}

if (!isSet($_GET['thumb'])) {
    exit;
}

$thumb_dir = $_SESSION['thumbpath'];
$thumb_file = $thumb_dir.'/'.$_GET['thumb'];

if ($thumb_dir === dirname($thumb_file)) {
    if (is_readable($thumb_file)) {
        header('Content-Type: image/jpeg');
        readfile($thumb_file);
    }
}
?>
I guess this code is relying on the user not being able to guess what directory the images are in as they would only see something like:

<img src="getthumb.php?thumb=001.jpg"/>

and not

<img src="clients/smith/images/001.jpg"/>

I still had the .htaccess on the 'clients' directory and when the thumbnail page opens up with twelve 'getthumb.php' requests I got asked for the htaccess user/pass 12 times...which I guess is logical.

I tried moving the image folder to outside the document root while maintaining the getpic script inside the document root. I changed the path to the images in the database to ../clients/smith/images.

Unfortunately this hasn't worked and I'm trying to hunt down why. Am I doing this right?

Would using $_SERVER['DOCUMENT_ROOT'] be wise and then using something like the directory = ../clients/smith/images??

Brad

Posted: Sat Nov 27, 2004 11:49 pm
by rehfeld
it wasnt meant to rely on the user not knowing, i just forgot to mention the htaccess part :)


yes you could use $_SERVER['DOCUMENT_ROOT']

and then ../ into it if you want. personally, i would just use htaccess though

in the images folder, (not the individual user folders)

put the following htaccess

note this will totally deny everyone from viewing ANYTHING inside that directory, including other directorys. but it wont stop your helper script of course.

Code: Select all

<Limit GET POST>
Order Allow,Deny
deny from all
</Limit>
but putting them above the doc root as you suggested would work just fine as well. some hosts dont let you go there, so if you ever switch hosts in the future, having it below the doc root and using htaccess might be more portable.

be VERY carefull when you set the $_SESSION['thumb_path']

i would recomend running that preg_match bit to only allow alphanumeric chracters on the variable input before you set that session var.



im not sure why its not working for you. try echo on the various paths to make sure they are what you think.

also, what are you setting $_SESSION['logged_in'] to?

true
or
'true'
?