Reputation: 4804
I'm trying to set up a PHP page that will safely accept a file upload (a resume), store it as a mysql blob, and provide a download later. But when I download the PDFs later for viewing, they always seem corrupted and won't open properly.
Thanks to a question by Jgoettsch (php: reversing mysql_real_escape_string's effects on binary), I realized that feeding the file data through mysql_real_escape_string (to prevent injection) might corrupt the file contents, and got the idea to pass the binary through base64_encode() instead, and use base64_decode() before download.
Here's some mockup code demonstrating what I'm doing currently (which is not working):
The upload:
<?
// Get file contents
$cv_pointer = fopen($_FILES['cv']['tmp_name'], 'r');
$cv_content = fread($cv_pointer, filesize($_FILES['cv']['tmp_name']));
fclose($cv_pointer);
// Insert SQL
$sql = sprintf("INSERT INTO documents (name, file, size, date_uploaded)
VALUES ('%s', '%s', '%s', NOW())",
mysql_real_escape_string($_FILES['cv']['name']),
mysql_real_escape_string($cv_content),
mysql_real_escape_string($_FILES['cv']['size']));
$result = mysql_query($sql);
?>
And the download:
<?
if (isset($_GET['view_cv'])) {
$cv = mysql_fetch_assoc($rsApplicationCv);
header("Content-length: ".$cv['size']);
header("Content-type: application/pdf");
header("Content-disposition: attachment; filename=".$cv['name']);
echo $cv['file'];
exit();
}
?>
Here are my questions:
Thanks in advance!
Upvotes: 0
Views: 1046
Reputation: 108390
Q If you have a file upload field, is that field vulnerable to sql injection?
A yes (sort of. It's not the fields on a form that are vulnerable to SQL Injection; the vulnerability is really in the code that handles the values submitted in the request.)
Q Or am I worrying unnecessarily?
A No. You should ALWAYS be aware of the potential for bad things to happen, and write your code in a way that prevents vulnerabilities from being exposed (and exploited.)
Q If I feed the uploaded file contents through base64_encode(), is that tantamount to sanitization?
A It's nearly there, as long as your base64_encode guarantees that the returned value will contain only [A-Za-z0-9+./=]. Best practice would be to use bind parameters
Q or should I encode it then additionally pass the encoded string through mysql_real_escape_string?
A barring the use of prepared statements with bind parameters, then best practice dictates that ALL values (including base64_encoded values) be run through mysql_real_escape_string if they are being included in SQL text to be submitted to the database.
Upvotes: 1
Reputation: 536
Since you're talking about sanitizing, I'm assuming this is for a public website where strangers will be uploading files. Storing user submitted PDF files is a very bad idea. Firstly, how can you be certain the file you're receiving is even a PDF? It's 100% possible for users to CURL a malicious file into your database and have users uknowingly download a virus. PDFs themselves (if I recall correctly) can actually glitch their way into executing viruses in certain Windows operating systems, just like WMV and WMA files can.
If you absolutely need a PDF, then the best option is to instead create your own PDF file with sanitized data submitted by a user. You can probably find a tutorial online on how to do this. I personally wouldn't recommend using PDFs in the first place since you can use HTML & CSS to build a resume and print it out perfectly.
Upvotes: 1