Uploading images with imagecreatefromjpeg() security question

Apologies if this is answered elsewhere. I was not able to find a similar post.

I need some expert advice on security issues with uploaded images in a PHP application.

Briefly, I have a web app that displays uploaded images as a slideshow. The images are uploaded by the user through a custom-built CMS (which is on the same domain as the public pages) and records are sent to a database that include the filename as it was on the user’s computer. Everything is working okay, however I decided to put the upload directory for the images outside or above the webroot, so e.g.

domain name points to public_html,
host/public_html/index.html is home page,
host/uploads/ is where the upload folder is

The images are now accessed in something like the following manner from the slidehsow page:
<?php
$query = “SELECT filename,imgID FROM pics”;
$result = mysqli_query($dbconnect,$query);
while($record = mysqli_fetch_array($result)) {
echo ‘<div class=“slide”><img src="fetch_image.php?file=’ . $record[‘filename’] .‘" id="slide_’ . $record[‘imgID’] . ‘" /></div>’;
}
?>

fetch_image.php looks something like:
<?php # fetch_image.php

if(isset($_GET[‘file’])) {

// Access the root directory
$root_dir = dirname(dirname(dirname(FILE)));

$file = $root_dir. ‘/uploads/’ . $_GET[‘file’];
$size = getimagesize($file);

if (file_exists($file) && $size) {
	header('Content-Description: File Transfer');
	header('Content-Type: application/octet-stream');
	header('Content-Disposition: attachment; filename='.basename($file));
	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: ' . filesize($file));
	ob_clean();
	flush();
	readfile($file);
	exit;
}

}

The divs with class ‘slide’ in the generated HTML have absolute positioning and display:none so all will stack up on top of each other and are hidden when the page loads. A javascript file controls the slideshow by showing and hiding instances of ‘slide’ according to thumbnail links clicked by the user.

This works a treat, however, and I’m coming to the point, considering that in the Content Management System the file upload script creates a copy of the uploaded file using imagecreatefromjpeg() and imagecopyresampled(), is this layer of security unecessary? In other words would it be safe to use relative links (e.g. /images/thefile.jpg) here and move the upload directory inside the webroot? There doesn’t seem to be a lag in performance as it is, but if there were 20 images that would be 40 page requests (there is a row of thumbnail images), does that make a significant difference to demands on resources and speed? I don’t know if having upload dir above webroot makes any difference at all in this situation.

BTW the upload script is part of a freely available file upload kit and I’m not sure if it’s permitted to place any lifted code from it here. It’s the jquery fileuploader.

I have been googling this subject for the past two days and am really surprised that such a common application of PHP is not better documented.

Any ideas on the subject would be most welcome.

Could you elabourate a bit. Do you mean absolute paths?

This part is the weakness,


$file = $root_dir. '/uploads/' . $_GET['file'];

Make sure you have an array of the files you have in uploads and check to see if it is in the array, $_GET[‘file’] could have the path …/evilfile.php or even a path to a domain.
If you allow the public to upload files, make sure they can’t upload files with .php .js and .htaccess codes. htmlPurifier can be your friend.

Thanks for pointing that out lorenw.

I would also use mysql_real_escape_string() before making a query too.

I think what I need is a pointer to a good book or online resource which will explain a bit more in depth about securing web apps such as this. I’m aware of the basic principles but feel like I’m getting lost in a mesh of security measures and circumventing code, and could probably do things in a much simpler way.

I’ll try to make it clearer what I’m asking.

If you look at the while loop in the code above you see that fetch_image.php is called as many times as there are images (twice in fact if you count the thumbnails). Does this amount to significant increase in overhead (over <img src=“standard_path_to_file.eg.” />). This is the kind of info I’m after. What’s the best way to do this and maintain security? If anyone can point me in the right direction.

Thanks