Secure downloads without authentication - php

I would like to create temporary links to prevent direct download of files.
The flow should be this:
user purchase the file, indicating only the email address -> sends an email to that address with the url to the temporary file purchased.
I wish this url is available only for 3 times.
How can I do this?
Using Symfony2 on apache server.
I apologize for the request extremely vague, but I'm going blind and I do not know what to look for to find a way.

Generate a random key, make a mysql table which contains fileid, key, number_of_downloads.
Every time the user clicks a link to http://www.yourdomain.com/getfile.php?file=blah&key=blahblah you can update the table number_of_downloads. If it's < 2, redirect to the file (use php header or symphony's redirect), if it's > 2, give a 404 or whatever...

It should be pretty simple (although I don't know much about Symfony2). You'll have a download page that gets a "key" parameter (maybe /download?key=blahblahblah). Make a database (or other sort of storage), and whenever you need to generate a download link, have your code make up a key and store it in the database. Each key could also have a number attached to it for the number of times it can still be used, or alternatively an expiration time. The download page would make sure the key is still valid, and if so serve up the file.
Edit: Here's an example of serving a file through a PHP script:
// this may need to change depending on the file type
header("Content-Type: application/octet-stream");
// this makes sure the downloaded file doesn't get named "download.php"
header("Content-Disposition: attachment; filename=stuff.zip");
// and this sends the file
echo file_get_contents("/path/to/stuff.zip");
Edit again: Actually, this is probably a better way.

Related

Prevent file access on direct http

My question seems to be similar to others here in SO, I have try a few but it doesn't seem to work in my case...
I have develop a site in which you have to fill up a form and then it returns a PDF file that you can download or print, this file is saved so you can retrieve it later
public_html
|_index.php
|_<files>
| |_file_001.pdf
| |_file_002.pdf
|_<asstes> ....etc
that is how my files and folders look on the server, anyone can easily guess other files, .com/folder/file_00X.pdf, where X can be change for any other number and get access to the file... the user after finish with the form the script returns a url .com/file/file_001.pdf so he/she can click on it to download...
a year ago I did something similar an script to generate PDF's but in that case the user needed the email and a code that was sent via email in order to generate the PDF and the PDF's are generated on demand not saved like in this case...
Is there a way to protect this files as they are right now?
or, do I have to make it a little bit more hard to guess?
something like.
.com/files/HASH(MD5)(MICROTIME)/file_(MICROTIME)_001.pdf
and save the file and folder name in the DB for easy access via admin panel, the user will have to get the full URL via email...
Any ideas would be greatly appreciated.
For full security i would move the PDFs out of the public folder and have ascript in charge of delivering the content. If the form is filled correctly, you can generate a temporary hash and store that hash and the pdf path in the database. That way the user will have access to the file as a link through the retriever script, but you will control for how long he will have that link available.
Imagine the temporary link being http://yourdomain/get_pdf/THIS_IS_THE_HASH
Move the PDF's to some non-public folder (that your web server has access to but the public does not). Or you can use .htaccess to restrict access to the pdf's in their current location.
Write a php script that returns the correct pdf based on some passed in http variable.
You can secure/restrict this any way that you want to.
For example, one answer suggested using a temporary hash.
Other options for restricting access:
Store in the user's session that they submit the form and have a download pending, that way no one could direct link.
Check the referrer header. If it is a direct request then do not serve the file.
Here is a code example using the last option:
$hash_or_other_identifier = $_REQUEST["SomeVariable"];
if (!$_SERVER["HTTP_REFERER"])
{
//dont serve the file
} else {
//lookup the file path using the $hash_or_other_identifier
$pdfFile = somelogic($hash_or_other_identifier);
//serve the correct pdf
die(file_get_contents($pdfFile));
}
I don't even think that keeping the file name secret is a very big deal if all you are worried about is people typing it into the URL bar because you can simply check if it is a direct link or not. If you are also worried about bots or clever people who will create a link that points to your file so it looks like a referrer, then you will need to add stricter checks. For example, you can verify that the referrer is your own site. Of course headers can be spoofed so it all just depends how bulletproof it needs to be.
The url would be something like: http://yourdomain/pdf?SomeVariable=12345
However, you don't have to use an http variable. You can also use a url fragment with the same result, eg: http://yourdomain/pdf/12345
General guidelines:
File is not in the directory that's accessible via HTTP
Use a database or any other storage to link up file location with an identifier (an auto incremented number, guid, hash, whatever you deem fit). The location of the file could be in the server's file system or on a shared network location etc.
Instead of hashes, it's also practical to encrypt the ID generated by the database, base64 encode it and provide it back - that makes it nearly impossible to guess the valid string that one needs to send back in order to refer to a file
Use a PHP script that delivers the file if user authentication passes (in case you need authenticated users to be able to retrieve the file)

storing pdf files on server securely

I am deploying a website from where user can purchase the pdfs. now i am searching for the way for storing the pdfs so that it only can be downloaded when payment is done.
I have came across one way in which i can store the pdfs in to the Mysql database and generate the path to it when required credentials fulfill.
Is there any other way to do this and link to the pdf file should be dynamic and encrypted so that other links to the other books can't be predicted.
and the server side language I am using is PHP
You need to store the files somewhere outside your website root like mentioned by Dagon. When file is uploaded use move_uploaded_file to move it. You can name the file anything you want (within OS limits) and keep the real name in the database.
Then when the user has payed for the books, add the books the user has payed for to a table in a db.
Give the user a list of all the books he has payed for like: /download/filename.pdf
Add a mod_rewrite if you use Apache (or equivalent for other web servers) where /download/.* is redirected to download.php or a controller.
On the download page, check if user is logged in and has access to the file. If not, redirect to purchase page for that book.
If download is ok set header for the http status you need: Content-Length, Content-Type, Date, Status (200), maybe Content-Encoding.
Use readfile to output the file to the end user.
I would :
Deny any access to the files -- i.e. use a .htaccess file (That way, no-one has access to the file)
Develop a PHP script that would :
receive a file identifier (a file name, for instance ; or some identifier that can correspond to the file)
authenticate the users (with some login/password fields), against the data stored in the database if the user is valid, and has access to the file (This is if different users don't have access to the same set of files), read the content of the file from your PHP script, and send it the the user.
The advantage is that your PHP script has access to the DB -- which means it can allow users to log-in, log-out, it can use sessions, ...
Here is another answer from a stack user that fits this problem: Creating a Secure File Hosting Server for PDFs
is there any other way to do this and link to the pdf file should be dynamic and encrypted so that other links to the other books can't be predicted.
The best way, is after payment generate a key to the file.
create a page like this www.site.com/download.php?key=key (and here you don't need to have id of the book, because by the key you can check on the database what is the book the customer purchased.
inside the download.php read the key, query the database to find which file is linked with the key
read the file, and send it to the customer. This is, if the key is valid, you will send the php headers as content type as being pdf, and (the php code) read the file in binary and send it in the message body.
I hope this code helps
<?php
// We'll be outputting a PDF
header('Content-type: application/pdf');
// It will be called downloaded.pdf
header('Content-Disposition: attachment; filename="downloaded.pdf"');
// The PDF source is in original.pdf
readfile('original.pdf');
?>

Hide download URL [duplicate]

This question already has answers here:
how to hide the actual download folder location
(3 answers)
Closed 8 years ago.
I'm trying to make the URL of a downloadable PDF document invisible to the user, so that they can't access it from anywhere else. I need to hide the URL from the bottom left of the page (when they mouse over) and the URL from the browser's address bar when they open it. I need it to work on all browsers.
My HTML looks like this:
View PDF
And the link should look like this:
View PDF
The reason is the user must provide a code to be able to download their document, but if they can see the URL they could easily download someone else's documents (They only have to change a digit in the "a34501.pdf" part).
I read something about using a JavaScript function to encrypt the URL, or use an external PHP file. However, I don't know how to do that.
Thanks.
Hiding the url will baffle the least tech savvy users, but not anyone who is willing to download your files and have a very minimal tech knowledge, if you need to hide your files behind a code (or pay wall) you can use a PHP script that authenticates the user and spits out the corresponding file, a small example is like this:
if($validUser)
{
$path = $fileName;
$size = filesize($path);
$fp = fopen($path, "rb");
$content = fread($fp, $size);
fclose($fp);
header("Content-length: ".$size);
header("Content-type: application/octet-stream");
header("Content-disposition: attachment; filename=".$fileName.";" );
echo $content;
}
exit();
This assumes you have the files physically in the server, but you can modify it if you have them in a database or any other storage medium. Of course, you must first validate if the user have the right to download that file but this is up to you.
You can use a php script to provide the document, while still allowing php to authenticate the user's session information/etc.
The process goes like this:
User enters a unique code (after additional authentication required to validate the user).
A unique document link is generated, such as: http://domain/download.php?file=58afg71057ga82157 (example)
download.php validates the user request against stored session information -- if everything checks out, it sends the file header() and passes along the file contents.
This basic file download tutorial provides the very basics of providing a file in this way. You will need to improve upon this basic tutorial, but it should give you an idea of how the process works.
Suggestions:
Use a unique "key" per user (allowing the same user to re-download); or,
A single-use key which only allows a single download, ever; or,
Require user authentication, so that you know whether they should be "allowed" to use the key.
Do not use a "filename.ext" to locate the file to download, either store the name in the session or use a unique identifier stored in a database.
Don't just copy paste an example scripts, they are often extremely insecure.

How Do I Hide Filename & extention in PHP?

I have a url in this format: "sitename.com/folder/file.php". How do I make it a "sitename.com/randomhash" or "sitename.com/folder/randomhash" format?
I know I can use a GET & Switch system but I need the name to be unique and I need to be able to change it on the fly.
I don't really understand what your point is, but if you don't want you're visitors to know where your php-files are stored, I would recommend reading this:
Tutorial for URL handling in PHP
If you are having a website where people can download stuff, and you don't want people hotlinking your files, you could do the following steps (i'm not writing the code, I'm just going to give you a general idea):
People come to your website.
Person clicks on link because they want to download that particular file.
Person comes on page, where you have the opportunity to set a cookie with a random hash.
Simultaneously you put a value in a database, with the same hash and the filepath of the file they want to download.
On this page, they have to click "DOWNLOAD NOW!", where they are redirected to download.php.
In download.php you read the cookie, then match that with the database and get the filepath.
With the right php-headers, you can force download.php to download the file.
Important in this situation is that you set your settings of Apache (or whatever server you have) that downloading is not allowed unless 'localhost' is requesting it.

Control Access to Filesystem with PHP

I previously posted here:
Controlling Access for Trial Subscription
Since this is a new question based on suggestions there, I thought I should start a new post. If this should have been an edit, please let me know for the future.
I think the solution I'm going with to control access will be to upload a file and hash the name. The file will be in the format:
/uploads/#############.pdf
A link will be sent to subscribers. The first time they come to the site, they'll be asked to create a "pin" and a "hint" to remember. Then can then access a landing page to list their items via an email address/pin combo.
My question is: I know I can control the access to the page that shows what items they can view, but is there a way to control the /uploads/[file] to only be download-able after some kind of programmatic check? I can't think of any way to do this....
Thanks again.
D.
Your pdf files don't have to be in a user viewable directory. They can be outside your web root. That way, noone can actually browse to www.yoursite.ext/uploads/2395wrfhgt.pdf to download it himself or share the link with others.
In order to download the pdf you'll have a dedicated script that will do all the access checks on the user that's requesting it, and if all ok it will set the appropriate headers, read the file from the filesystem, and print it out to the user.
So, lets say your site is at /var/www/site/htdocs/ and you upload every pdf into /var/www/site/uploads/ . You don't even need to hash the filenames but instead can keep them nicely named for easy organization.
Then, all the links to download a file will be made to point to www.yoursite.ext/download.php?id={fileid}
Your download.php will do all the access checks (properly logged in, has permissions to download the file etc), and then do the following:
$pathToPdf = '/var/www/site/uploads/some.pdf' ;
header('Content-Type: application/pdf');
header('Content-Length: ' . filesize($pathToPdf));
header('Content-Disposition: attachment; filename=' . 'some.pdf');
readfile($pathToPdf) ;
And that's pretty much it. Once you get this working you can look into improving a few things:
use mod_rewrite or similar to have the actual pdf filename in the link, which helps some browsers realize they should download it: www.yoursite.ext/download/{fileid}.pdf
consider using the web server instead of php to serve files, eg X-Sendfile header

Categories