PHP - Protecting digital Downloads - php

I'm trying figure out how I can protect digital downloads in PHP. Just need some general directions so I can start my research. I don't seem to be able to find anything useful.
I want to make files available for my users to download but don't want them to be able to directly access a download folder. Also, I want the download link to be available only for set period of time or a single download.
Could some one point me in the right direction?

The best way is to delegate the download managment after your check to the mod for apache
x_sendfile
https://tn123.org/mod_xsendfile/
Usage:
<?php
...
if ($user->isLoggedIn())
{
header("X-Sendfile: $path_to_somefile");
header("Content-Type: application/octet-stream");
header("Content-Disposition: attachment; filename=\"$somefile\"");
exit;
}
?>
<h1>Permission denied</h1>
<p>Login first!</p>
Basically when you send the header X-Sendfile the mod intercepts the file and manages the download for you (the file can be located whenever you want outside the virtualhost).
Otherwise you can just implement a simple file download.php that gets the id of the file and prints the contents with readfile after the login check

Just some examples: You can place your files outside of the webserver's document root or in a directory that is protected by a .htaccess file with a "deny from all" rule; then you deliver the files by a custom PHP function that sets the correct headers (mime-type, filesize etc.) and returns the file.
You could create links with unique id's based on MD5 or SHA1 hashes - a mod_rewrite rule points the id to your PHP file, you lookup the id in the database and do your time checks, like
example.com/downloads/73637/a8d157edafc60776d80b6141c877bc6b
is rewritten to
example.com/dl.php?id=a8d157edafc60776d80b6141c877bc6b&file=73637
Here's an example of doing something you want with nginx and PHP:
http://wiki.nginx.org/HttpSecureLinkModule

"Secure Download Links", a PHP Script can be used to hide download url or rename download file, it has option for storing below web root and for files stored above webroot that is with absolute http urls also.

Related

restrict file download php

I have this in my code:
Sample PDF
So basically it will appear to be a download link to file 'sample.pdf' but the problem is, there's a restriction in downloading this file. so whenever there are confidential reports uploaded and a malicious user accidentally memorized or viewed the URL of the download link in the browser history he can easily download it even without accessing the website because it is a direct link. What am i supposed to do so this link will be protected? or be downloaded only for the user assigned to it?
Don't serve up files by their direct URLs. Have a PHP script receive the filename of the file wanted, and serve it up.
So, if someone wants to download the above files, he would go to
example.com/getfile?file=sample.pdf
Your PHP script would check if the current user has permission to view the file, and then serve it up.
Make your links like this:
Sample PDF
Your current method is very insecure for sensitive files. A malicious user could trivially write a script to download ALL files in res/pdf. All he needs to do is check every permutation of letters in the directory, and throw away all 404 errors.
You will not redirect the user since that would defeat the purpose. You will serve the file as a download with the appropriate Content-disposition header.
Here's an example: Fastest Way to Serve a File Using PHP
You can google and get many more examples.
Here's a great example that shows how to serve PDF files:
https://serverfault.com/questions/316814/php-serve-a-file-for-download-without-providing-the-direct-link
You can restrict using htaccess

What is the best way to protect a digital goods directory so that it can only be accessed by a PHP script?

My site interacts with the PayPal Digital Goods API which on completion redirects back to my PHP script which then allows the download.
I would like to know the best way to protect the directory containing digital goods which is outside of the web root.
At the moment I am protecting the directories by removing all permissions. When the download script is called the permissions of the directory containing the digital good are changed to allow the download then removed again. Below is a shorthand version of what's happening in the script.
chmod('/digital/goods/directory/file', 0777);
readfile(file);
chmod('/digital/goods/directory/file', 0000);
I'am sure this cant be the right way to do this. Could you use htaccess without the user having to enter the user and password? Any pointers would be appreciated.
Ensure the files aren't being served directly. In Apache, you would keep them out of the DocumentRoot.
Then, the permissions shouldn't matter, since there is simply no URL that maps to them.
Store your digital goods above the DocumentRoot, and then serve via a PHP script with a unique hash for each purchaser
ie)
DocumentRoot: /home/user/public_html/store
Protected Folder /home/user/goods
With PHP use:
Readfile() see http://php.net/manual/en/function.readfile.php
and use something like this to serve the file:
<?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('/home/user/goods/original.pdf');
?>

Access html files / video files outside htdocs folder

Trying to protect video files that are done in camtsia which outputs html/with flash embed video files.
Not sure how I would access them using PHP. I've searched stackoverflow and found using alias would be an option? Is that still secure though? Is that the best way to go? Or should I try to purue a file open operations using PHP.
It needs to serve an html page which has .js .swf files along in the same protected dir.
Any help or direction is appreciated.
You would use readfile to access the file and the header function to forge the content. Make sure the www-data user, which is the Apache user and PHP uses it to access the filsystem, has permission on that folder.
header('Content-type: video/avi');
header('Content-Disposition: attachment; filename="videodownload.avi"');
readfile('/var/videos/myvideo.avi');

Convert the uploaded files to specific file format which can not download

I have a problem regarding to prevent download and saving of uploaded files.
My users can upload multiple files types like doc, pdf, ppt,etc....
This all file types are easily download if any one have url.
So what is the better way to prevent the download of the file.
Or i convert the uploaded files to some specific format which can not download easily (e.g flash)..
I am running on php and mysql.
Thanks
Avinash
You have two options in this regard. The first is to move the files, through a PHP script, to a server-side folder outside of the server's web directory. The second is to store the files in a BLOB column in a MySQL table. Both will prevent users from accessing the files directly, without the need to convert the file to a not-so-easily-downloaded format.
Upload the files outside of your document root. For example:
/var/username/uploads/file.docx
where your document root is
/var/username/public_html/index.php
So they can't be accessed directly. And then if you want to allow downloads, create a PHP file called "download.php" that does something similar to:
$data = file_get_contents('/var/username/uploads/file.docx');
header('Content-Type: application/docx');
header('Content-Length: '.strlen($data));
header('X-Content-Type-Options: nosniff');
echo $data;
and obviously you can add checks to see if the user has the proper permissions to download this particular file or is logged in.
A solution can be to set a user and a password to the upload folder, so only the users that know authentification details can download files.
Check next link for learn how to make htpasswd files on your server folders:
http://httpd.apache.org/docs/1.3/programs/htpasswd.html

Performance-oriented way to protect files on PHP level?

I am looking for some input on something I have been thinking about for a long time. It is a very general problem, maybe there are solutions out there I haven't thought of yet.
I have a PHP-based CMS.
For each page created in the CMS, the user can upload assets (Files to download, Images, etc.)
Those assets are stored in a directory, let's call it "/myproject/assets", on a per-page basis (1 subdirectory = 1 page, e.g. "/myproject/assets/page19283")
The user can "un-publish" (hide) pages in the CMS. When a page is hidden, and somebody tries to access it because they have memorized the URL or they come from Google or something, they get a "Not found" message.
However, the assets are still available. I want to protect those as well, so that when the user un-publishes a page, they can trust it is completely gone. (Very important on judicial troubles like court orders to take content down ... Things like that can happen).
The most obvious way is to store all assets in a secure directory (= not accessible by the web server), and use a PHP "front gate" that passes the files through after checking. When a project needs to be watertight this is the way I currently go, but I don't like it because the PHP interpreter runs for every tiny image, script, and stylesheet on the site. I would like have a faster way.
.htaccess protection (Deny from all or similar) is not perfect because the CMS is supposed to be portable and able to run in a shared environment. I would like it to even run on IIS and other web servers.
The best way I can think of right now is moving the particular page's asset directory to a secure location when it is un-published, and move it back when it's published. However, the admin user needs to be able to see the page even when it's un-published, so I would have to work around the fact that I have to serve those assets from the secure directory.
Can anybody think of a way that allows direct Apache access to the files (=no passing through a PHP script) but still controlling access using PHP? I can't.
I would also consider a simple .htaccess solution that is likely to run on most shared environments.
Anything sensitive should be stored in a secure area like you suggested.
if your website is located at /var/www/public_html
You put the assets outside the web accessible area in /var/www/assets
PHP can call for a download or you can feed the files through PHP depending on your need.
If you kept the HTML in the CMS DB, that would leave only non-sensitive images & CSS.
If you absolutely have to turn on and off all access to all materials, I think your best bet might be symlinks. Keep -everything- in a non-web-accessible area, and sym link each folder of assets into the web area. This way, if you need to lock people out completely, just remove the symlink rather than removing all files.
I don't like it, but it is the only thing I can think of that fits your crtieria.
I'd just prevent hotlinking of any non-HTML file, so all the "assets" stuff is accessible only from the HTML page. Removing (or protecting) the page just removes everything without having to mess up the whole file system.
Use X-Sendfile
The best and most efficient way is using X-Sendfile. However, before using X-Sendfile you will need to install and configure it on your webserver.
The method on how to do this will depend on the web server you are using, so look up instructions for your specific server. It should only be a few steps to implement. Once implemented don't forget to restart your web server.
Once X-Sendfile has been installed, your PHP script will simply need to check for a logged in user and then supply the file. A very simple example using Sessions can be seen below:
session_start();
if (empty($_SESSION['user_id'])){
exit;
}
$file = "/path/to/secret/file.zip";
$download_name = basename($file);
header("X-Sendfile: $file");
header("Content-type: application/octet-stream");
header('Content-Disposition: attachment; filename="' . $download_name . '"');
Important note:
If you are wanting to serve the file from another webpage such as an image src value you will need to make sure you sanitize your filename. You do not want anyone overriding your script and using ".." etc. to access any file on your system.
Therefore, if you have code that looks like this:
<img src="myscript.php?file=myfile.jpg">
Then you will want to do something like this:
session_start();
if (empty($_SESSION['user_id'])){
exit;
}
$file = preg_replace('/[^-a-zA-Z0-9_\.]/', '', $_GET['file']);
$download_name = basename($file);
header("X-Sendfile: $file");
header("Content-type: application/octet-stream");
header('Content-Disposition: attachment; filename="' . $download_name . '"');
EDIT: How about a hybrid for the administrative interface? In the ACP you could access via the PHP method to, basically, send all file requests to the PHP authing file, but for public, you can use HTTP AUTH/htaccess to determine the availability of the result. this gives you the performance on the public side, but the protection on the ACP side.
OLD MESSAGE:
.htaccess is compatible with most Apache and IIS<7 environments (using various ISAPI modules) when using mod_rewrite type operations. The only exception is IIS7 + the new Rewrite module which uses the web.config file. HOWEVER, I'd be willing to be that you could efficiently generate/alter the web.config file for this instance instead of using .htaccess.
Given that, you could set up redirects using the rewrite method and redirect to your custom 404 Page (that hopefully sends the proper 404 header). It is not 100% appropriate because the actual asset should be the one giving a 403 header, but... it works.
This is the route I would go unless you want to properly create HTTP AUTH setups for every server platform. Plus, if you do it right, you could make your system extendable to allow other types in the future by you or your users (including a php based option if they wanted to do it).
I'm assuming the 'page' is being generated by PHP and the 'assets' should not require PHP. (Let me know if I got that wrong.)
You can rename the assets folder. For example, rename '/myproject/assets/page19283' to '/myproject/assets/page19283-hidden'. This will break all old, memorized links. When you generate the page for admin users that can see it, you just write the urls using the new folder name. After all, you know whether the page is 'hidden' or not. The assets can be accessed directly if you know the 'secret' url.
For additional security, rename the folder with a bunch of random text and store that in your page table (wherever you store the hidden flag): '/myproject/assets/page19283-78dbf76B&76daz1920bfisd6g&dsag'. This will make it much harder to guess at the hidden url.
Just prepend or append a GUID to the page name in the database and the resource directory in the filesystem. The admin will still be able to view it from the admin interface because the link will be updated but the GUID effectively makes the page undiscoverable by an outside user or search engine.
Store your information in a directory outside the web root (i.e.: one directory outside of public_html or htdocs). Then, use the readfile operator in a php script to proxy the files out when requested. readfile(...) basically takes a single parameter--the path to a file--and prints the contents of that file.
This way, you can create a barrier where if a visitor requests information that's hidden behind the proxy, even if they "memorized" the URL, you can turn them down with a 404 or a 403.
I would go with implementing a gateway. You set a .htaccess file to the /assets/ URL pointing to a gateway.php script that will deny if both the credentials are not valid and this particular file is not published or show it.
I'm a little confused. Do you need to protect also the stylesheet files and images? Perhaps moving this folder is the best alternative.

Categories