views:

483

answers:

8

I'm serving up documents that require the user to register before download. Currently, once you register and login, the links to the documents are displayed as:

myurl.com/docs/mypdf.pdf

So the physical path to the document is exposed to anyone logged in. What is the best practice for keeping the physical path to the document hidden so registered users can't share direct links with unregistered users or post direct links to the documents elsewhere?

EDIT: I was just looking for an idea that was language agnostic so I chose a few of my favorite languages for the tags. The actual implementation in this case is ASP classic. I'm currently using a download wrapper script that confirms the user is logged in before redirecting to the actual document URL. I just didn't include it in my question for simplicity.

+8  A: 

The best way is to read the file up from a non-web accessible path and write it to the output stream.

This seemed to show an OK example in php which you seemed to be using? Just add security check to top of php and kick them out if they are not authorized.

http://www.higherpass.com/php/Tutorials/File-Download-Security/

j0tt
It could be a good idea to use the webserver to transparently translate http://myurl.com/docs/mypdf.pdf to http://myurl.com/docshandler.php?file=mypdf.pdf, and docshandler handles the authentication before sending the file, or showing an error message.
Osama ALASSIRY
+1  A: 

the best way to do that is to use a php/asp or serverside scripting file that reads the document a location that isnt available to the outside

that file then can check if the user is logged in and it can also hide the path to the physical file

so the url would be www.yourwebsite.com/file.php?file=image.png

file.php would verify that the user is logged in then it would read the file or redirect them to the login page

Jim
A: 

It's not clear if you're using ASP.NET, ASP.NET MVC or something else. However, this post...

http://stackoverflow.com/questions/730699/asp-net-mvc-how-do-i-code-for-pdf-downloads

... shows how to programatically return a file to the user using ASP.NET (the question shows the ASP.NET way, the answers show the MVC way).

THis would allow the physical files to be in a folder not otherwise accessible to the user, and would allow you to add validation prior to returning the document to ensure that the user was registered etc.

If you're at a stage in your development where it's not too late to use ASP.NET MVC then do so. This scenario (serving up a file) becomes a one-liner, and so many other things will be easier (in particular, the testing of your app).

Martin Peck
+11  A: 

Don't do that. Instead keep the files somewhere outside the document tree and then make them accessible using a script (eg, php, .Net, whatever)

The script can check if they are logged in, validate if they are allowed the file, and if so return it. The path they go to might look more like this... /download.php?file=mypdf.pdf

Something along the lines of...

<?php
if (IsUserLoggedIn())
    readfile('/secret/path/to/file/mypdf.pdf');
?>
rikh
A: 

You could use a IHttpHandler in .net, although you need wildcard access in IIS. You could use a session based handler.

Elijah Glover
+1  A: 

What you want to do is create a PHP page that does two things:

  1. authenticate the user that is making the request
  2. stream the file to the client

This link will help with streams. And this code may be helpful:

header("Content-Disposition: attachment; filename=$name of pdf that you want to download");
header("Content-Type: application/pdf");
header("Content-Length: ".filesize("$location of pdf/$name of pdf that you want to download"));
header("Pragma: no-cache");
header("Expires: 0");
$fp=fopen("$location of pdf/$name of pdf that you want to download","r");
print fread($fp,filesize("$location of pdf/$name of pdf that you want to download"));
fclose($fp);
exit();

Saw this in a discussion here.

Vincent Ramdhanie
there is a typo in the first header line: Content-Disposition: attachment;
Eineki
fixed - thanks for the heads up.
Vincent Ramdhanie
A: 
  1. Use a script for access control

    Make a script like myurl.com/file.php?docs/mypdf.pdf which checks that the user has rights to access the file. The script will fetch the file from a place that is not visible to the web.

  2. (Optional) Use mod_rewrite to make your urls look nice, and redirect user to the file.php script. Something like:

    RewriteCond docs/%{REQUEST_FILENAME} !-f

    RewriteRule ^(.*)$ file.php/$1 [QSA,L]

    This will redirect /docs/mypdf.pdf to /file.php?docs/mypdf.pdf but look nicer for the user.

abababa22
+1  A: 

I had a similar problem many moons ago in classic ASP.

Kept files in a directory outside of the webroot.

Upon verification, sent the file via ADODB.Stream, and then checked the file extension to make sure i had the proper mime-type set.

NoCarrier