This is a discussion on Password protecting downloads within the alt.comp.lang.php forums, part of the PHP Programming Forums category; I'm in the middle of developing a website with a downloads section. It's a wad of educational software ...
|
|||||||
| FAQ | Members List | Calendar | Search | Today's Posts | Mark Forums Read |
|
|||
|
I'm in the middle of developing a website with a downloads section.
It's a wad of educational software for an LEA which for obvious reasons needs password protecting. Users have to authenticate before being allowed to search and getting a link to the download. Don't want the users to get at the files without logging in first, so I created a script (filedownload.php) that adds the filename to the URL query string (e.g., filedownload.php?file=file1.zip) filedownload.php then simply prepends the full name of where the files live: header("Location: http://www.xyz.com/fileslivehere/file1.zip"); I thought this would do the job so the user wouldn't get to see the full URL on screen, but I've just realised it appears in the browser history (At least in IE, haven't checked Mozilla or others.) I don't have shell access to the web server so this must be PHP only, or achievable with shell commands executed via PHP. I was thinking about copying a 'master' file to a temporary random file name but most of the files are 200-300 meg so I'd like to avoid this, then there's the problem of knowing if the file has downloaded okay to delete the temporary file[1]. I'd say this isn't a new problem! How have others achieved the same thing on their sites? |
|
|||
|
Iain Napier wrote:
> I'd say this isn't a new problem! How have others achieved the same > thing on their sites? It may not be the easiest solution, but it is the most effective.. considering storing the files in a mysql database. Many people forget you can easily store and retrieve binary data from the db. This way, you can highly control when and if the data stream is sent to the user from the db, and it's nearly impossible for anyone to get data out of it without properly authenticating via your scripts.. using this method, there is no direct http path to the file. Secondly, you can store the files outside of the webroot.. sounds like you're using shared hosting here, so instead of putting the files in your public_http, put them somewhere else, then your download script just sources that file, whereever it is (fopen) and sends it.. -- alex ~ alex@aeshells.org ~ www.aeshells.org ~ www.aeirc.net ~ USER, n.: The word computer professionals use when they mean "idiot." |
|
|||
|
alex wrote:
> > It may not be the easiest solution, but it is the most effective.. > considering storing the files in a mysql database. Many people forget > you can easily store and retrieve binary data from the db. This way, > you can highly control when and if the data stream is sent to the user > from the db, and it's nearly impossible for anyone to get data out of it > without properly authenticating via your scripts.. using this method, > there is no direct http path to the file. This certainly sounds the most secure option. Is this likely to give the server much of a performance hit? > Secondly, you can store the files outside of the webroot.. sounds like > you're using shared hosting here, so instead of putting the files in > your public_http, put them somewhere else, then your download script > just sources that file, whereever it is (fopen) and sends it.. This is interesting. However FTP'ing into the server dumps me chroot'd in wwwroot so I can't directly upload files elsewhere, perhaps a PHP script would allow me access to some other directories on the server though? (Is this likely?) If I could execute a shell script from PHP to create another directory and move uploaded files to it that could be a workaround. I'll rustle up a script tomorrow to test it (It's nearly 3am!) |
|
|||
|
alex wrote:
> > Secondly, you can store the files outside of the webroot.. sounds like > you're using shared hosting here, so instead of putting the files in > your public_http, put them somewhere else, then your download script > just sources that file, whereever it is (fopen) and sends it.. I've just realised I can change permissions on this server, so if I create a subdirectory in wwwroot called privatearea, put my file1.zip in there and remove the public read permission, a web browser can't get it's hands on it. Now, I create a test.php in the same directory as file1.zip and using $_SERVER['PATH_TRANSLATED'], I get the full file system path to where my files are. So: $file="/full/path/to/my/wwwroot/privatearea/file1.zip" if ($file_handle=fopen($file,"r")) echo("PHP can read the file!"); And I see PHP can read the file okay, but web browsers don't get direct access to it. Presumably I can now use fopen to send the data back via PHP? Thanks for the pointer in your first post, I seem to be on the right track now I hope. Tomorrow I'll try and work out how to have PHP send the file back.. 3.30 am now :-\ |
|
|||
|
Iain Napier wrote:
> alex wrote: > >> >> Secondly, you can store the files outside of the webroot.. sounds like >> you're using shared hosting here, so instead of putting the files in >> your public_http, put them somewhere else, then your download script >> just sources that file, whereever it is (fopen) and sends it.. > > > I've just realised I can change permissions on this server, so if I > create a subdirectory in wwwroot called privatearea, put my file1.zip in > there and remove the public read permission, a web browser can't get > it's hands on it. it's been awhile since i used any shared hosting (three or four years at least), but if it's *nix based (you don't use a windows host.. do you?) you should have some sort of a /home/user dir.. normally including your public_http, maybe a public_ftp, normally also an etc, and a few others depending on your host for all the settings and such pertaining to your account.. your host could of course be different. > > Now, I create a test.php in the same directory as file1.zip and using > $_SERVER['PATH_TRANSLATED'], I get the full file system path to where my > files are. So: > > $file="/full/path/to/my/wwwroot/privatearea/file1.zip" > if ($file_handle=fopen($file,"r")) echo("PHP can read the file!"); > > And I see PHP can read the file okay, but web browsers don't get direct > access to it. > > Presumably I can now use fopen to send the data back via PHP? > > Thanks for the pointer in your first post, I seem to be on the right > track now I hope. Tomorrow I'll try and work out how to have PHP send > the file back.. 3.30 am now :-\ here is a bit of a script i use to open an a file and send it to the client.. you can use this to help.. (keep in mind, when we send headers, they must be the first thing sent, you can't have any output go to the client first) (also, using this method, i always use the ob buffer.. so all the headers and file stream are sent at the same time.. works this way for me.. ymmv #------------------------------------ ob_start(); header('Content-type: application/x-gzip'); header('Content-Disposition: attachment; filename="' . $file . '"'); header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT"); header("Cache-Control: post-check=0, pre-check=0", false); header("Pragma: no-cache"); readfile($dir . $file); ob_end_flush(); #------------------------------ be sure to modify the content-type for whatever you're sending -- alex ~ alex@aeshells.org ~ www.aeshells.org ~ www.aeirc.net ~ USER, n.: The word computer professionals use when they mean "idiot." |
|
|||
|
Following on from Iain Napier's message. . .
>I'm in the middle of developing a website with a downloads section. >It's a wad of educational software for an LEA which for obvious reasons >needs password protecting. Users have to authenticate before being >allowed to search and getting a link to the download. > >Don't want the users to get at the files without logging in first, so I >created a script (filedownload.php) that adds the filename to the URL >query string (e.g., filedownload.php?file=file1.zip) > >filedownload.php then simply prepends the full name of where the files live: Fine (when set to point outside the web root) so long as you know that your security model is "the key's under the mat". Ie. the you can't revoke permission to a single user, and you've opened up the complete archive to all users. BTW here is your starter for 10. How steps should you take to stop somebody trying to access the php sources by trying out a few possibilities like "filedownload.php?file=../www/filedownload.php"? -- PETER FOX Not the same since the bottom fell out of the bucket business peterfox@eminent.demon.co.uk.not.this.bit.no.html 2 Tees Close, Witham, Essex. Gravity beer in Essex <http://www.eminent.demon.co.uk> |
|
|||
|
alex wrote:
> > here is a bit of a script i use to open an a file and send it to the > client.. you can use this to help.. (keep in mind, when we send > headers, they must be the first thing sent, you can't have any output go > to the client first) (also, using this method, i always use the ob > buffer.. so all the headers and file stream are sent at the same time.. > works this way for me.. ymmv > > #------------------------------------ > ob_start(); > header('Content-type: application/x-gzip'); > header('Content-Disposition: attachment; filename="' . $file . '"'); > header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT"); > header("Cache-Control: post-check=0, pre-check=0", false); > header("Pragma: no-cache"); > readfile($dir . $file); > ob_end_flush(); > #------------------------------ > > be sure to modify the content-type for whatever you're sending That's worked brilliantly. I've removed the world read attribute for all the files, and used your chunk of code there to look at their absolute path on the web server. No clients can view them directly via a browser, but they can read them fine going via authentication then your script. Just want I wanted! Many thanks :-) |
|
|||
|
Peter Fox wrote:
> > Fine (when set to point outside the web root) so long as you know that > your security model is "the key's under the mat". Ie. the you can't > revoke permission to a single user, and you've opened up the complete > archive to all users. > > BTW here is your starter for 10. > How steps should you take to stop somebody trying to access the php > sources by trying out a few possibilities like > "filedownload.php?file=../www/filedownload.php"? Hi Peter, Thanks for the comments. All the filenames are stored in a MySQL database, and the filename is validated against what's in there before filedownload.php allows the user to get it. |
|
|||
|
"Iain Napier" <emailaddressisinvalid@aol.com> wrote in message news:XNednQLDfMJoGD7eRVnyuQ@pipex.net... > alex wrote: >> >> Secondly, you can store the files outside of the webroot.. sounds like >> you're using shared hosting here, so instead of putting the files in your >> public_http, put them somewhere else, then your download script just >> sources that file, whereever it is (fopen) and sends it.. > > I've just realised I can change permissions on this server, so if I create > a subdirectory in wwwroot called privatearea, put my file1.zip in there > and remove the public read permission, a web browser can't get it's hands > on it. > > Now, I create a test.php in the same directory as file1.zip and using > $_SERVER['PATH_TRANSLATED'], I get the full file system path to where my > files are. So: > > $file="/full/path/to/my/wwwroot/privatearea/file1.zip" > if ($file_handle=fopen($file,"r")) echo("PHP can read the file!"); > > And I see PHP can read the file okay, but web browsers don't get direct > access to it. > > Presumably I can now use fopen to send the data back via PHP? a better function might be readfile() because it reads the file and outputs straight to the browser. all you need before it is header()s. > > Thanks for the pointer in your first post, I seem to be on the right track > now I hope. Tomorrow I'll try and work out how to have PHP send the file > back.. 3.30 am now :-\ |