how to set headers in php for safety - php

I'm being told to find the unsafe in this code and find a way to fix it.
Someone can help me ?
<?php
$file_url = 'upload/news'.$_GET['file'];
header('Content-type: application/octet-stream');
header("Content-Transfer-Encoding: Binary");
header("Content-disposition: attachment; filename=\"". basename($file_url)."\"");
readfile($file_url);
?>

The $_GET['file'] usage in the $file_url exposes the code to path traversal attacks. This is quite a dangerous setup, any file in the news directory can be read, if you place sensitive files like .env in the news folder they can be read!
If all content should be public you can use pathinfo to ensure you only get filenames. Checkout the following example:
$fileName = basename($GET['file']);
$fileUrl = 'upload/news/'. $fileName
header('Content-type: application/octet-stream');
header("Content-Transfer-Encoding: Binary");
header("Content-disposition: attachment; filename=\"". $fileName."\"");
readfile($fileUrl);
basename is safe to use in this case because it removes any path part that could be used for path traversal
basename("../test.php"); // test.php
basename("."); // .
basename("../.."); // ..
basename("../../test.php"); // test.php

Related

Downloading a file in php doesn't work for pdf but works for text files

I am trying to force download a file in my php program under a new name (new_name). I am changing the file name but keeping the extension the same as roginal file. This is part of my code:
$original_filename = "attachments/20180315.log";
$new_filename = "new_name." . pathinfo($original_filename, PATHINFO_EXTENSION);
header("Content-Length: " . filesize($original_filename));
header("Content-Transfer-Encoding: binary");
header('Content-Disposition: attachment; filename="' . $new_filename . '"');
header('Pragma: no-cache');
readfile($original_filename);
exit;
My download is working fine when I am downloading a text file (i.e. in example above 20180315.log is a text file). When I try to do the same with a binary file (such as pdf) I am getting an empty new_name.pdf.
Any suggestion?
I have always found the exact headers required to be a bit messy and dependent on the browser, there are a lot of options, and you will see a lot of variations posted, so i suggest the following, but you may need to just test a number of combinations until you get it right, and i suggest making sure you test it on as many browsers as you can.
header('Content-Type: application/octet-stream');
header("Content-Transfer-Encoding: Binary");
header("Content-disposition: attachment; filename=\"" . $new_filename . "\"");
readfile($original_filename);

Content-Disposition downloading wrong file

I am trying to download a file. I am using IE11. I have tried several methods to do this. Currently I am trying to use the header with Content-Disposition method. I have tried to do this a few different ways according to other answers people have given. And it does download. But instead of downloading the file I point it to, it downloads the file it is written in. So if I tell it to download example.txt in my test.php file. It will only download test.php.
These are the methods I have tried:
This one is written in test.html:
<?php
$filename = "example.txt"
header('Content-Type: text/plain');
header('Content-Disposition: attachment; filename="' . basename($filename) . '"');
?>
I've also tried making it a button:
BUTTON
Where download.php is:
<?php
$file = $_GET['file'];
header('Content-type: audio/mpeg');
header('Content-Disposition: attachment; filename="'.$file.'"');
?>
I tried this:
<?php
header('Content-Type: application/download');
header('Content-Disposition: attachment; filename="example.txt"');
header("Content-Length: " . filesize("example.txt"));
$fp = fopen("example.txt", "r");
fpassthru($fp);
fclose($fp);
?>
And this:
header("Content-Disposition: attachment; filename=\"" . basename($File) . "\"");
header("Content-Type: application/force-download");
header("Content-Length: " . filesize($File));
header("Connection: close");
There are many more slight variations and mix and matching that I have tried. All have the same problem that the .html or .php file downloads rather than example.txt. Does anyone know why this would happen? Is something not supported in IE11? I do not think it is a syntax error simply because most of these I copied from other answers online. I have tried with example.txt existing and not existing, in this folder and other folders.
EDIT: So it turns out that these all work, I was just using them wrong. I had been trying to make isolated files to run this code so I could test it without interference from the rest of the functions on my website, but this left the php files without the resources they needed to actually run properly. When I put the code into the actual files on the website it worked perfectly. smh
Try this :
header('Content-Description: File Transfer');
header('Content-Type: application/octet-stream');
header('Content-Length: ' . filesize($File));
header('Content-Disposition: attachment; filename=' . basename($File));
readfile($File);
exit;

Using readfile on multiple devices?

I'm having a bad time with the readfile function on php. I'm setting up a web file server, but many of the users have problems with the downloads.
Basically, I'm using Chrome on my computer and everything works fine. Some of the users have problems on Android browser: they get a .bin file instead og .doc, or get a correct .doc file, but they can't open it. Also, someone gets a corrupted .doc file on the computer.
I have read many questions on this site but they weren't so helpful.
Since I have tried many solutions, I will post a shortened code snippet to give an idea of what I am trying to accomplish. I am using apache2, couldn't it be a configuration problem?
Does someone have my problems too?
<?php
//here I take the user, the pwd and the file RELATIVE path
//there are no errors here
header('Content-Description: File Transfer');
header('Content-Type: application/octet-stream');
header('Content-Transfer-Encoding: Binary');
header('Content-disposition: attachment; filename="' . $name . '"');
readfile($file);
?>
EDIT: full code
<?php
session_start();
$data = $_SESSION['data'];
$name = $_GET['name'];
if (isset($data)) {
//private file
$file = "path/".$data."/".$name;
} else {
//public file
$file = "path/public/".$name;
}
header('Content-Type: application/octet-stream');
header("Content-Transfer-Encoding: Binary");
header("Content-disposition: attachment; filename=\"" . $name . "\"");
readfile($file);
?>

readfile function for PDF download issues

I know this question has been asked, but the solutions offered are not working for me. I am able to download PDFs, but Adobe Reader is telling me it's either corrupt or decoded improperly. Does anyone have an alternative solution, or possible fix?
$path = "http://www.laerdalmail.com/discoversimulation/downloads/needs_assessment_form.pdf";
header('Content-Type: application/pdf');
header("Content-Transfer-Encoding: Binary");
header("Content-disposition: attachment; filename=needs_assessment_form.pdf");
readfile($path);
exit;
readfile should be given a filesystem path, not a URL. something like this:
$path = '/websitefolder/discoversimulation/downloads/needs_assessment_form.pdff';
// or
$parh = 'c:\something\needs_assessment_form.pdff';
Try adding in content length too:
header('Content-Transfer-Encoding: binary');
header('Content-Length: ' . filesize($path));

Download automatically a file(.sql) in wwwroot using PHP

So far here what i've tried it can download the sql file but it is empty
//test.php
<?php
header("Content-type: application/octet-stream");
header('Content-Disposition: attachment; filename=wordpress_db1.sql');
?>
Here is what my root folder look like
I want to download the wordpress_db1.sql file when I run the test.php but I always get empty on it. How can I fix this? thanks!
Below code will do the trick for you.
<?php
$file_name = 'file.sql';
$file_url = 'http://www.example.com/' . $file_name;
header('Content-Type: application/octet-stream');
header("Content-Transfer-Encoding: Binary");
header("Content-disposition: attachment; filename=\"".$file_name."\"");
readfile($file_url);
?>
What have you gone wrong is readfile($file_url);. Setting headers will not get the job done. you have use readfile($file_url);
Setting the headers doesn't read the file. You can name the file anything you want in the attachment. You have to actually emit the file:
readfile('wordpress_db1.sql');

Categories