Preventing direct image link?

PHP programming forum. Ask questions or help people concerning PHP code. Don't understand a function? Need help implementing a class? Don't understand a class? Here is where to ask. Remember to do your homework!

Moderator: General Moderators

bradles
Forum Commoner
Posts: 89
Joined: Wed Jun 30, 2004 10:40 pm

Preventing direct image link?

Post 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.
peni
Forum Commoner
Posts: 34
Joined: Thu Nov 18, 2004 1:15 pm

Post by peni »

you can controll the access by checking referers, afaik.
hedge
Forum Contributor
Posts: 234
Joined: Fri Aug 30, 2002 10:19 am
Location: Calgary, AB, Canada

Post by hedge »

store the folders outside of the webserver root.
bradles
Forum Commoner
Posts: 89
Joined: Wed Jun 30, 2004 10:40 pm

Post by bradles »

Hedge,

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

Brad
bradles
Forum Commoner
Posts: 89
Joined: Wed Jun 30, 2004 10:40 pm

Post 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.
User avatar
phpScott
DevNet Resident
Posts: 1206
Joined: Wed Oct 09, 2002 6:51 pm
Location: Keele, U.K.

Post by phpScott »

is your directory structure such

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

??
hedge
Forum Contributor
Posts: 234
Joined: Fri Aug 30, 2002 10:19 am
Location: Calgary, AB, Canada

Post 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?
bradles
Forum Commoner
Posts: 89
Joined: Wed Jun 30, 2004 10:40 pm

Post 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
rehfeld
Forum Regular
Posts: 741
Joined: Mon Oct 18, 2004 8:14 pm

Post 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;
bradles
Forum Commoner
Posts: 89
Joined: Wed Jun 30, 2004 10:40 pm

Post 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
rehfeld
Forum Regular
Posts: 741
Joined: Mon Oct 18, 2004 8:14 pm

Post 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/";
bradles
Forum Commoner
Posts: 89
Joined: Wed Jun 30, 2004 10:40 pm

Post 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
rehfeld
Forum Regular
Posts: 741
Joined: Mon Oct 18, 2004 8:14 pm

Post 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
bradles
Forum Commoner
Posts: 89
Joined: Wed Jun 30, 2004 10:40 pm

Post 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
rehfeld
Forum Regular
Posts: 741
Joined: Mon Oct 18, 2004 8:14 pm

Post 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'
?
Post Reply