Should content-transfer-encoding headers be use when downloading files via HTTP? - php

I recently came across How to force file download with PHP which describes setting Content-Transfer-Encoding. Is this header applicable when used with this application when used to download a file via HTTP (it appears to be email related)? If so, what should it be set as for MS Word and Excel files, ZIP files, PDFs, and Text?
header("Content-Transfer-Encoding: Binary");

It has been religiously included by carg-cult copy-paste programmers since it was mentioned in a comment to the readfile() manpage on PHP.net.
It indeed has little to do with HTTP and you can safely remove it.

Related

Chrome and Firefox prevent downloading a dynamically created zip file saying it is an unusual download and could be harmful

Google Chrome and Mozilla Firefox classify my zip file as potentially harmful.
This is what users see when downloading the zip file
I wrote some peace of code (PHP, Codeigniter) which creates a zip file dynamically and let's the user download it immediately. This peace of code is only reachable after an user login. On localhost everything works fine but on production Google Chrome and Mozilla firefox classify the zip file as potentially harmful.
The production is HTTPS encrypted with a domain validated certificate by RapidSSL.
I did some research and found:
Since zip is a binary file and the website itself is not known enough, the download is generally classified as untrustworthy.
If it were a static file accessible via a public URL, Google would inspect it sooner or later and then classify it as safe. Since these are dynamically created ZIP files that can only be accessed in the login area, this option is no longer available.
It could be that the SSL certificate is not secure enough because it is only domain validated. Before I buy a more expensive one here, I wanted to hear your opinion about this possible solution. Will a better certificate ensure that the Zip files are considered safe?
I don't have my software in the Google Search Console. Could that do anything?
During my research I came across the http header "Content Security Policy". Would setting this header be the solution?
I tried both codeigniter zip library and PHP's ZipArchive. Both solutions had the same problem. The headers I set for downloading after creating the zip file with PHP's ZipArchive are the following:
//Set the Content-Type, Content-Disposition and Content-Length headers.
header("Content-Type: application/zip");
header("Content-Disposition: attachment; filename=$zip_name");
header("Content-Length: " . filesize($zip_path_and_filename));
//Read the file data and exit the script.
readfile($zip_path_and_filename);
exit;
I expected that the zip file will be downloaded without classifying it as potentially harmful. In fact Microsoft Edge does not complain anything.

File not found issue in php

<?
header("Content-type: octet/stream");
header("Content-Transfer-Encoding: Binary");
header("Content-disposition: attachment; filename=a.mp3");
readfile("http://adstorage.jamba.net/storage/view/325/0/fa/Fairytale.mp3");
?>
This code is working great in my localhost but displays File not found when uploaded to my server
Do you have PHP permissions to read external files?
These permissions might be different on your local machine and the web server.
According to the readfile() documentation:
A URL can be used as a filename with this function if the fopen wrappers have been enabled. See fopen() for more details on how to specify the filename. See the Supported Protocols and Wrappers for links to information about what abilities the various wrappers have, notes on their usage, and information on any predefined variables they may provide.
*Please set the file permission so only it can be working correctly.. *
I don't think the code you've posted has anything to do with the 404. A code error with your mp3 download would not produce a 404.
Chances are your CodeIgniter setup is wrong/different on your remote host. Check the routing is working. Do other controllers work?

Forcing to Download A File

I'm developing a web service. With this service, user's will upload their .php files, and service will remove UTF8 BOM characters from php file. And then, There will be a link like this :
Download Your File
But when i click this link, browser browsing to this file. I don't want browse it, i want to download it. So , when user click this link, downloading will start.
Any ideas ?
(P.S. I don't want modify uploadedfile.php file, also i read 5 questions about this, but still i have problem.)
You need to supply this HTTP header:
Content-Disposition: attachment; filename=example.txt
You can usually specify this for entire directories at a time by configuring your web server appropriately. If you mention which web server you are using, somebody may be able to suggest how to do this.
The problem is that you're allowing people to upload PHP files on your server, then giving them a link to execute that PHP file. The web server is automatically treating those uploaded PHP files like any other PHP file, i.e. executing it, which opens you up to a massive security hole.
Whatever purpose your web service has, I'd suggest renaming the file on your server when it is uploaded (something 'random' is best, without an extension), then having a PHP script feed it back out with the appropriate headers set when it is requested.
The URL for such a script would look like:
http://www.example.com/get_uploaded_file.php?id=jgh3h8gjdj2389
It would link the value in id with the file on the server, and if you've saved the original filename somewhere (flat file, DB), you can serve it out using its original name, so long as you set the right HTTP headers.
Linking directly to the PHP file may end up executing it. One way is (like somebody above suggested) to rename it. Or, you can have a downloader.php which does below:
<?php
header('Cache-Control: no-cache, must-revalidate');
header('Expires: Mon, 01 Jan 2000 01:00:00 GMT'); // some date in past
header('Content-type: text/plain');
header('Content-Disposition: attachment; filename='.basename($filepath));
header('Content-Length: ' . filesize($filepath));
flush(); // or any other flush function/mechanism you use.
readfile($filepath);
and link it something like:
Download
This method will let you retain the .php extension. Also, if the PHP file is big and connection is slow, they progress-bar would be accurate (because you've flushed the content length upfront.

Php readfile - Force Download

I am using a flash player to play some mp3 files. At firefox it loads them normally but at IE it doesn't. When i go to the url of the .mp3 file it shows the source code of the mp3 (instead of offering eg to download). So i used a small script to fix it:
$url = $_GET['url'];
header('Content-type: application/force-download');
header('Content-Transfer-Encoding: Binary');
header("Content-disposition: attachment; filename=demo.mp3");
readfile($url);
I would like to ask you if the above is safe. Moreover, does the server losses bandwidth by this way? And finally, does it influence the server's resources?
Thanks.
No, that's not safe. If you had your database password in database.php and I entered database.php as $_GET['url'], your script would send me that PHP file with your password in it.
Yes, this would use up bandwidth and some server resources.
It's not safe, and it shouldn't be necessary for you to do this way.
In addition to the security implications #ceejayoz outlines, if the allow_url_fopen PHP setting is enabled, it is also possible to insert any URL into $url. That way, your server could be easily misused to stream large amounts of data from other servers, with all kinds of implications.
This method of serving files should be used only when really necessary. It consumes more resources (because an expensive PHP process has to be started) than requesting a static resource through the web server.
It should not be necessary in your case anyway. It sounds like your web server is not serving the correct content-type header along with your MP3 files. That is what you should fix.
Maybe, if you're on Apache, adding a .htaccess file to the directory the MP3s are in with the following content:
AddType audio/mpeg .mp3
already fixes the problem. If it doesn't, but the force-download thing works, then try
AddType application/force-download .mp3
Your actual problem is that you are not sending the content-type header to the client when you serve the mp3 file. Ensure that you are setting the content-type header prior to sending the contents of the mp3 file.
If you're serving them directly from your web server, without a script, you simply need to configure the content-type in your web server's configuration.
For Apache, you can configure this in an .htaccess file:
AddType audio/mpeg .mp3
Yeah there is definitely a security risk here since you aren't validating/sanitizing the requested file path. So make sure you check that before sending files down to the user!
Although this will use bandwidth and server resources, it would be minimally more than downloading files regularly. The only extra overhead is processing/running the PHP. You probably won't notice a difference.

How to let users with required permission download a file via php?

I have a php file that acts as a gatekeeper for all the files I want people to download, who ahve sufficient privilages.
The code I use throw the file to the user is
header('Content-Description: File Transfer');
header('Content-Type: application/octet-stream');
header("Content-disposition: attachment; filename=\"".$public_filename."\"");
header("Content-Transfer-Encoding: Binary");
header('Expires: 0');
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
header('Pragma: public');
header("Content-length: ".$f_filesize);
readfile($file_path);
Most files are fairly large.... 400mb-10GB.
What would be a good way to do this, and keep the true locations + filenames secret, so people cant just link to the files directly, but HAVE to link thru my download.php?file=ID gatekeeper?
Thanks
EDIT: Im not asking how to do user authentication, all that is done. Im just asking if my way of doing it, is a good idea on a large scale. Seems like it could cause memory problems if I keep reading 10GB files.
Ok, having php send files of around 400Mb–10Gb is not good. You need to somehow let whatever webserver you're using actually serve the files.
This really comes down to how secure you need it to be. The easiest solution that comes to mind (but far from the most secure) is using symbolic links with long random names that link to the original file. After a certain time the symbolic links expire and are removed. Each user get their own symbolic link (or "token") to the file they're downloading. I'm not sure how this plays out in Windows-environment, but on unix it's fairly straightforward anyway.
Here's some pseudo code:
if($user->isAllowedToDownload($file)){
$token = md5($user->name . $file->name . time() . $someGoodRandomValue);
symlink($file, $download_path . $token);
header("Location: $download_url$token");
}
Then you need a cron job that cleans out old symbolic links. You also need to make sure the webserver is set to follow symbolic links, preferably only for that folder where these download tokens are created.
So when the user maybe requests domain.com/download?file=bigfile.mp4 a symbolic link is created in the webservers public space that points to the real file outside the webservers public space. The user gets redirected to maybe domain.com/getFile/ab739babec890103bdbca72 which in turn causes the webserver to serve the file. Now it's very hard for users to try and guess what an URL is for a file, and that's the "security".
You're already doing that - the $public_filename is what you want it called, the readfile($file_path) part is the file - it's location isn't made public. Past that, it could be above the document root.
Put the files somewhere that is not accessible via HTTP.
Create a database table of file IDs with file paths.
Link to the files via file ID (as you noted above, download.php?fileID=0000).
???
Profit.
As someone who did this previously (many years ago), you need to consider the memory impact this will have on your server. The readfile function was not available then, so it is possible you may not need to do anything special for memory considerations.
You'll want to somehow authenticate them (an HTML form, HTTP basic auth, whatever), then set a session flag, which your download.php script can check. Note that this doesn't prevent people from downloading the file, then distributing it themselves.
You should configure your web server so the real files are not directly accessible.
It's not going to cause memory problems per se. readfile does not read the file into memory. However, using PHP will create overhead. You can eliminate some of this delay by using X-Sendfile.
Your method will cause memory problems, however it is possible to read and output the file in chunks. You will need to use flush() function after you echo each chunk of file. You can also make resuming downloads to work with a little more effort. Still this is an CPU hungry approach.
The easier and better solution is to use "x-sendfile" header tag supported by both apache and lighttpd through their modules. All you'll have to do is just specify file name in your header, similar to this:
header('X-Sendfile: filename-on-your-file-system');
Link for lighttpd:
http://redmine.lighttpd.net/projects/lighttpd/wiki/X-LIGHTTPD-send-file

Categories