Click to See Complete Forum and Search --> : PHP: securing files
vhg119
03-07-2005, 08:52 PM
Lets say I have an online photo album service that I would like to secure with usernames+passwords. There are more than one account.
I want php to handle authentication.
The php generates a photo album based on the username+password you provide it. The photos are jpegs kept on some directory within the root.
The problem that I am having is this:
Any user who knows the direct path to an image can view the image, bypassing the security implementation.
What techniques exists to secure the images?
I don't want to use apache authentication because I want php to handle authentication.
Thank you.
Vince
j79zlr
03-07-2005, 09:11 PM
Store the images in a MySQL db.
fatTrav
03-07-2005, 09:41 PM
If you don't want to store the the files into a database, you could store the photos in a directory named with a string of random chars (to prevent guessing) and store each photo using a random filename. This would prevent guessing. If you had apache turn off directory indexing, then no one could just go to the directory (if they had its name) and get a listing of files.
Username/password use a database to handle that -- trivial.
Securing the files, I haven't made up my mind which idea I like better. I don't like storing (possibly) large files in a database but if the files are extremely sensitive then I'd consider doing so because it is easier to limit who gets to make what database queries than it is to prevent someone from accessing served files--because at the point of the query to get a photo the user should already be logged in the system.
Maybe check sourceforge/freshmeat to see if something like this already exists.
vhg119
03-07-2005, 10:48 PM
fatTrav,
You're talking about security through obscurity. But this still doesnt protect againts people who have the path. Say someone logs into your computer and checks the history bar. It wouldnt defend against that.
Just in case you're wondering.. I'm not really creating a photo album. I'm creating an online "webdrive" storage system for my users. (I don't know why I didn't mention it the first time) The system will store files as if it were a network attached drive.. but accessible through the webpage only.
Since these files may get pretty large, storing them in a database may not be very practical. Or is it?
vince
bwkaz
03-07-2005, 11:09 PM
It might work to put the images outside the DocumentRoot of your webpage, so they're not accessible via direct paths at all. Then, make a small PHP script that takes the name (or ID, or whatever) of an image, and returns the image using whatever PHP function you can use to write a file to the output.
You could store the real filename path in a database, along with an ID number that you'd use to view the files. You could even store the username in the same table, so you'd know who had access to what files.
So even if a user was to look at your PC's history, they'd see URLs of http://yourserver/whatever/view.php?id=45, ?id=46, ?id=47, etc., etc. This view.php script will require an authentication cookie (or whatever PHP uses), of course, so they can't even use those URLs. And they can't get a valid login to the server and then look at your file IDs, if you store the username in the ID->path table and then be sure to check it inside the script.
Using an ID rather than the full path also prevents against arbitrary file-inclusion attacks on the PHP script. (If you put the full pathname as the parameter, for example, then someone might request http://yourserver/whatever/view.php?path=/etc/passwd to try to get at your password file. Better to store the path in a database, so you have control at that level over what the user can see.)
vhg119
03-08-2005, 12:12 AM
bwkaz,
I'm not sure if I can pipe the file as an output that way. I have to use http since its going through apache and apache needs to know the source of the file.
I guess I could have the php code copy the file from an undisclosed location to the DocumentRoot for that session. But that might have efficiency problems.
Thank you for the replies guys. I'm interested to know how the pros do it. Too bad I dont know any
Vince
thaddaeus
03-08-2005, 12:23 AM
do a search on google for php photo album scripts or check out hotscripts.com, there is a way to basically hide the location of the file, and the program netjuke does this with music files. I belive php also has image drwing capbilities (or somthing like that) which may be useful
check out this link for most php functions
http://us2.php.net/quickref.php
ph34r
03-08-2005, 09:50 AM
Write a script that displays the images in php, use mod_rewrite to redirect any jpeg requests to that script with the desired jpeg as an argument.
bwkaz
03-08-2005, 07:39 PM
Originally posted by vhg119
I'm not sure if I can pipe the file as an output that way. Even with this:
http://us3.php.net/manual/en/function.fpassthru.php
or this:
http://us3.php.net/function.readfile
? I know I've used "readfile" myself, but it seems that fpassthru is actually a bit safer (it may not hit the memory limit -- readfile slurps the whole thing in at once). You'll have to do a header("Content-Type: image/jpeg"); or similar first, of course.
ph34r -- that might work, except it won't stop people from requesting http://server/that-page.php?imagename=/etc/passwd from the script that you're redirecting to. If you store the path in a database, attackers can't pass a fake one to your PHP script for you.
vhg119
03-08-2005, 10:49 PM
I guess I'll just have to obfuscate the filenames and have a mysql db store all the metadata.
I can't do anything about people who know the path; at least not for now.
Thanks everyone.
vince
bwkaz
03-09-2005, 07:49 PM
Originally posted by vhg119
I can't do anything about people who know the path; at least not for now. Why can't you put the pictures outside Apache's DocumentRoot, again? Did I miss where you addressed that before?
vhg119
03-10-2005, 01:11 AM
If I put files outside DocumentRoot, how can I get to them? Aren't images on a web page referenced by an address such as '<img src='something/pic.jpg' />'?
I hope I'm missing something and there's another way of doing this.
Vince
thaddaeus
03-10-2005, 03:40 AM
check th link i provide, there are jpeg and gif and such fucntions to basically use the image from elseware in your site
the imagecreatefrom... function is what you need
dboyer
03-10-2005, 05:07 AM
Originally posted by vhg119
fatTrav,
You're talking about security through obscurity. But this still doesnt protect againts people who have the path. Say someone logs into your computer and checks the history bar. It wouldnt defend against that.
Just in case you're wondering.. I'm not really creating a photo album. I'm creating an online "webdrive" storage system for my users. (I don't know why I didn't mention it the first time) The system will store files as if it were a network attached drive.. but accessible through the webpage only.
Since these files may get pretty large, storing them in a database may not be very practical. Or is it?
vince
I did something similiar on a windows server at work a couple years ago. All the students at the school had accounts on the system with roaming profiles that loaded a folder on the server at d:\username\ to the users box at z:\... all the folders had NTFS permissions set... this php program would jsut try and do directory listings... if that failed, it would prompt for permissions, and theyd have to log in there... if that succeeded the script would allow them to do basic file managing tasks...
Of course, that was on a Windows box... :)
vhg119
03-10-2005, 12:12 PM
Gosh, I really shouldn't have used the photo album example.
What I'm really trying to do is build a webdrive system to store files on my webserver and retrieve them from somewhere else. So, I'm not just storing images. Sorry for the confusion.
Are there functions for general binary files similar to the image piping ones? For instance, if my code saves the file to somewhere off the DocumentRoot and saves the path to a DB, then I create a link on a page to retrieve the file, is there a way to pipe that file to apache?
Vincent
bwkaz
03-10-2005, 07:41 PM
Originally posted by vhg119
Aren't images on a web page referenced by an address such as '<img src='something/pic.jpg' />'? Yes, but just so you know, the file extension that you put on the 'src' attribute is totally irrelevant to the fact that they're images.
Your <img> tag's 'src' attribute would point to a PHP script that is inside your DocumentRoot. (The src will be something like "/blah/get.php?id=5423452" for file number 5423452.)
This script will first check the authentication cookie (or however you're storing authentication info). If that's OK, then it will read the record from the database, fopen() the path that's stored in the table, do a header("Content-Type: image/jpeg"); (or whatever -- the Content-Type is what defines the image's real format, so you'll just have to make sure you can get that information from somewhere for each file), fpassthru() the file handle, and then fclose() it.
The fpassthru() function is what writes the file's contents to the client through the HTTP socket. fpassthru() will work on any file, you just have to have the correct Content-Type: header so the browser will know how to display it.
You really should read the PHP function reference pages I linked to... ;)
vhg119
03-10-2005, 08:42 PM
bwkaz,
That is the perfect answer to my question. I looked at the links you sent me but didn't realize that it'll work on an element within a webpage. I thought they were meant to send files but not nested images for use with html formatting.
Thanks again!
Vincent
bwkaz
03-10-2005, 10:55 PM
Originally posted by vhg119
I thought they were meant to send files but not nested images for use with html formatting. Um?
I really doubt it will work to put them into a PHP file that has other HTML markup in it. You need to have it in a separate PHP-only script, which is referenced by the <img> tag's src attribute.
Or maybe you meant that, and I'm misunderstanding what you're saying?
vhg119
03-11-2005, 12:16 AM
LOL.. yeah, I did mean that... Nevermind.
Thanks again.. everything's all good now.
I'm having success with fpassthru().
VINCE