scriptygoddess

12 Dec, 2002

Secure downloads

Posted by: Jennifer In: Scripts

For the past couple of days, I've been working on creating a script that will allow for secure downloads. That is, let's say you have a file, but you don't want this file sitting on the root. You already have some sort of login script in place, so people can't access the page without logging in, but how do you get the download to work *through* the script with the file outside the web root…

A LOT of research went into this… I'll link to two sites that were most helpful:
php-builder and then most helpful with a single function: experts-exchange (the files I was trying to download were rather large)

Now here's the code:
(not really going to go into a great length of description here – this post is more like my notetaking…)

I create a "download.php" page with this in it:

<?
$fullpath = "/home/pathtofile/outsideofwebroot/downloadfolder/".$_REQUEST["download"];
$downloadstringarray = pathinfo($_REQUEST["download"]);
$p = $downloadstringarray["basename"];
$file_size = filesize($fullpath);
if (file_exists($fullpath)) {
//header("Content-type: application/zip");
// might need the above… left it in here for future possible use –
// although the line below worked with zips
header("Content-type: application/octet-stream");
header("Content-Disposition: attachment; filename=\"$p\"");
header("Content-Transfer-Encoding: binary");
header("Content-length: ".(string)($file_size));
if(strpos($_SERVER['HTTP_USER_AGENT'], 'MSIE')){
// IE cannot download from sessions without a cache
header('Cache-Control: public');
}
readfile($fullpath);
}
else
{
print "not found";
die();
}
?>

Then, I link to downloads like this:

<a href="download.php?download=folderinside/downloadfolder/file.zip">download this</a>

(add in "authentication both on the page that has the link – as well as the download.php page) – an easy "authentication" for this could be not allowing any access to the download.php page unless the referrer is the one you specify (that was one of the scripts I'd found, but wasn't applicable to the project I'm working on)

Update: actually, if you call "session_start() before that stuff? It dies. So my "authentication" flew out the window… so instead – I use that referrer check. But rather than enter in EVERY SINGLE PAGE of my site that referrences this download page – I check to make sure it's just coming from my site and folder where these pages are…

so above the code I posted above, put this:

$path_parts = pathinfo($_SERVER['HTTP_REFERER']);

Then I wrap the download code in this if statment:

if($path_parts["dirname"] == "http://www.YOURDOMAIN.com/pathtomy/folder") {
…etc…. (code from above)….
} else {
echo "you are not authorized to download this page!";
}

Updated to add: This probably goes without saying, but if you're getting errors withe filesize() and your file is in fact LESS than 2GB in size – check to make sure there are no spaces in the file name!!! (grrr) (If it's OVER 2GB, as far as I can tell – PHP can't handle doing it)

9 Responses to "Secure downloads"

1 | Jennifer

December 12th, 2002 at 11:27 pm

Avatar

If anyone needs it – I can "clean up" this code so it's usable to more than just me. 😉 Let me know…

2 | Jayant

December 13th, 2002 at 2:08 pm

Avatar

You can also protect files (from non referers) using the process of hot-linking, requires apache.

This can apply to all images (image protection), direct linking to pages/files you dont want ppl to directly link

3 | Jennifer

December 14th, 2002 at 7:50 am

Avatar

The problem(s) I had (that's really what the solution above is for) was a) it was on a windows server b) the downloads had to be purchased first/were for customers only.

4 | Jayant

December 15th, 2002 at 7:04 am

Avatar

In that case you can have added security by not disclosing the filename
as in
header("Content-Disposition: attachment; filename=\"$p\"");

instead have
//
code here to get only the file extension of $p
stored in $ext
//
header("Content-Disposition: attachment; filename=\"".rand().".$ext\"");

make sure you do srand() with timestamp, to generate a unique random number each time. they will think the file name as this :)

5 | Jason D-

December 19th, 2002 at 11:20 am

Avatar

What you need to parse for in the requested file var is .. since someone could post a link in any dynamically generated portion of the site to circumvent the referer check and start traversing the tree on the server and picking up different important OS files and having them sent to them. In the example code you have I could post

../../../../etc/passwd as my requested download and have it send me your passwd file and see who's got login accounts on your box and start attacking them.

6 | Jennifer

December 19th, 2002 at 2:42 pm

Avatar

Ahh.. good point.
Would you just strip them out? (therefore causing the hack to just have an error?)
or if they're in there, it means it's a hack attempt – so just forward the person out to someother page…?

7 | Jennifer

December 19th, 2002 at 2:45 pm

Avatar

actually – since it's checking for the referrer first – how would this even be possible? How does one "fake" a referrer?

8 | Hadley

December 31st, 2002 at 4:02 pm

Avatar

It's fairly easily to fake a referrer. How does your server know what page I last visited? The browser I'm using sends a http referer header saying where I came from. Obviously the browser doesn't need to tell the truth.

I think a more secure way would be thave an array of downloadable files, and then specify numerically which one to download.

Hadley

9 | John

February 4th, 2003 at 5:31 am

Avatar

Dont suppose it would be possible to get this code I am trying to do something similar but am new to php etc.I want clients to be able to download a file after they have gone through an order process.

would this work or does anyone know of a script that would.

Thanks John

Featured Sponsors

Genesis Framework for WordPress

Advertise Here


  • Scott: Just moved changed the site URL as WP's installed in a subfolder. Cookie clearance worked for me. Thanks!
  • Stephen Lareau: Hi great blog thanks. Just thought I would add that it helps to put target = like this:1-800-555-1212 and
  • Cord Blomquist: Jennifer, you may want to check out tp2wp.com, a new service my company just launched that converts TypePad and Movable Type export files into WordPre

About


Advertisements