Allowing website visitors to upload files is always fraught with danger when it comes to security, as a website visitor could potentially upload anything onto you’re server!
One of the most dangerous and very real risks is a website visitor uploading a PHP script onto your server (often through an upload form) and then commanding the server to execute the script internally by typing in the URL. This is a simple strategy to ‘hack sites’ and has been around for decades, but still catch’s countless server administrators, developers and webmasters out every day.
There are several strategies to help mitigate this risk which include:
1. Ensure your webserver is running under a ‘non-privileged user’
An essential misconfiguration to check is that PHP and the web-server (often apache) is not running and executing scripts as ‘root’ as this could allow an attacker to obtain complete control over the entire server an all sites on it.
If you are using Shared Hosting or a panel such as cPanel, this step isn’t applicable for you.
However if you purchased a VPS or followed a guide online on how to setup a web-server it’s something you want to check over as bad guides
In most instances the apache web-server user will be running under the user ‘www-data’, this can be checked by running the following command in terminal as the root user.
ps aux | egrep '(apache|httpd)'
Checking your PHP scripts are not being executed as the root user is also important, in most cases php related processes will be executed under the user of each website account.
2. Restrict what file types can be uploaded, (ie only image and document files)
Sometimes the simple solutions are the best ones! If a user cannot easily upload the script, it makes it significantly more harder for them to run it!
By default WordPress and most CMS platforms will restrict what types of files can be uploaded and block unsafe extensions, however if you are making your own forms be sure to add some server side protections such as below to check file types.
// Define allowed image extensions
$allowed_extensions = array('jpg', 'jpeg', 'png', 'gif');
// Check if the extension is in the list of allowed extensions
if (in_array(strtolower($extension), $allowed_extensions)) {
// Process the uploaded image
// Move the uploaded file to a permanent location
move_uploaded_file($_FILES['image']['tmp_name'], 'uploads/' . $filename);
echo "Image uploaded successfully!";
} else {
// Invalid file type
echo "Error: Only JPG, JPEG, PNG, and GIF files are allowed.";
}
3. Restrict what file types the web server can serve out of the folder
Restricting what file types can be served from a particular directory is a good way to ensure file types you don’t intend to be uploaded, be viewable by your web application or be accessible by the uploader should they be able to upload it.
The best way to do this is to append the following codeblock to the top of your upload directories ‘.htaccess file’ or create the file if one does not exist.
This code block will tell the webserver to only serve jpg, jpeg and pdf from the directory (such as yoursite/uploads) and return a 403 error for other unexpected file types
# Put this codeblock in your .htaccess file
# Deny access to all files
<FilesMatch "\.">
Order Allow,Deny
Deny from all
</FilesMatch>
# Allow access only to JPG, JPEG, PNG, and PDF files (ammend as required)
<FilesMatch "\.(jpg|jpeg|png|pdf)$">
Allow from all
</FilesMatch>
4. Set A Maximum File Size
Capping the maximum upload size is a sensible method to stop visitors from intentionally and even accidentally filling up your server with very large files.
It is not the first time we have seen sites go down due to a huge movie file being uploaded instead of a simple picture!
One of the easiest ways to do this is to modify the PHP post and upload_max file size which restricts how large a file a user can upload. This can be done through the PHP settings of your service hosting service, or values manually set in the .htaccess file.
# Limit file size and POST requests to 20MB
php_value upload_max_filesize 20M
php_value post_max_size 20M
5. Disable PHP Execution in the Untrusted Folder
The final way to ensure PHP scripts are not executed in untrusted directories is to tell the webserver to ‘switch off’ and not execute .php scripts in that particular directory.
This is done by adding the following codeblock into the .htaccess of the directory you do not wish php to be executed on. The most effective way to block PHP execution is to set the PHP hander to ‘text/plain’ telling the webserver to just show the script or to block the
# Display PHP scripts as plaintext and do not execute
<FilesMatch "\.php$">
SetHandler text/plain
</FilesMatch>
Alternativly you can restrict the web server from accessing PHP scripts if you did not set a whitelist in step 3.
# Deny access to PHP files
<FilesMatch "\.php$">
Order Allow,Deny
Deny from all
</FilesMatch>
6. Disable Indexing
When storing files in a directory, it is essential to ensure ‘indexing’ is disabled to prevent a list of all files from being generated if a visitor browsers the folder path.
This can be easily either by adding the below line to the .htaccess file for the directory, or creating a blank index.html file.
Options -Indexes
If you have any questions on these steps or further suggestions please let us know in the comments below