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:
- PHP – Securing your Web Application : Introduction
- PHP – Securing your Web Application : Filter Input
- PHP – Securing your Web Application : Cross-Site Scripting
- PHP – Securing your Web Application : SQL Injection
- PHP – Securing your Web Application : Escape Output
- PHP – Securing your Web Application : Filenames
- PHP – Securing your Web Application : Session Fixation
- PHP – Securing your Web Application : File Uploads
- PHP – Securing your Web Application : File Access
- PHP – Securing your Web Application : PHP Code
- PHP – Securing your Web Application : Shell Commands
- PHP – Securing your Web Application : More information and Summary
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.