PHP – Securing your Web Application : File Uploads

File uploads combine two dangers we’ve already discussed: user-modifiable data and the filesystem. While PHP 5 itself is secure in how it handles uploaded files, there are several potential traps for unwary programmers.

Distrust Browser-Supplied Filenames Be careful using the filename sent by the browser. If possible, do not use this as the name of the file on your filesystem. It’s easy to make the browser send a file identified as /etc/passwd or /home/rasmus/.forward. You can use the browser-supplied name for all user interaction, but generate a unique name yourself to actually call the file. For example:

$browserName = $_FILES['image']['name'];
$tempName = $_FILES['image']['tmp_name'];

echo "Thanks for sending me {$browserName}.";
$counter++; // persistent variable
$filename = "image_{$counter}";
if (is_uploaded_file($tempName)) {
	move_uploaded_file($tempName, "/web/images/{$filename}");
}
else {
	die("There was a problem processing the file.");
}

Beware of Filling Your Filesystem

Another trap is the size of uploaded files. Although you can tell the browser the maximum size of file to upload, this is only a recommendation and does not ensure your script won’t be handed a file of a larger size. Attackers can perform a denial of service attack by sending files large enough to fill up your server’s filesystem.

Set the post_max_size configuration option in php.ini to the maximum size (in bytes) that you want:

post_max_size = 1024768 ; one megabyte

PHP will ignore requests with data payloads larger than this size. The default 10 MB is probably larger than most sites require.

Surviving  register_globals

The default variables_order processes GET and POST parameters before cookies. This makes it possible for the user to send a cookie that overwrites the global variable you think contains information on your uploaded file. To avoid being tricked like this, check that the given file was actually an uploaded file using the is_uploaded_file() function. For example:

$uploadFilepath = $_FILES['uploaded']['tmp_name'];

if (is_uploaded_file($uploadFilepath)) {
	$fp = fopen($uploadFilepath, 'r');
	if ($fp) {
		$text = fread($fp, filesize($uploadFilepath));
		fclose($fp);

		// do something with the file's contents
	}
}

PHP provides a move_uploaded_file() function that moves the file only if it was an uploaded file. This is preferable to moving the file directly with a system-level function or PHP’s copy() function. For example, the following code cannot be fooled by cookies:

move_uploaded_file($_REQUEST['file'], "/new/name.txt");

Here is the list of of Article in this Series:

Please share the article if you like let your friends learn PHP Security. Please comment any suggestion or queries.

 

Thanks Kevin Tatroe, Peter MacIntyre and Rasmus Lerdorf. Special Thanks to O’Relly.