I'm doing a file upload system but I want to avoid uploading files
shell or virus to attack the page
but how do I do that?
$file = $_FILES["file"];
move_uploaded_file($file["tmp_name"], "archivos/$user_username/" . $file["name"]);
I'm doing a file upload system but I want to avoid uploading files
shell or virus to attack the page
but how do I do that?
$file = $_FILES["file"];
move_uploaded_file($file["tmp_name"], "archivos/$user_username/" . $file["name"]);
You can make the input that receives the files accept only some types (for example only images). That is the most obvious solution, but you are putting yourself in the case that someone simply renders an executable. I would say that there are three paths that are not mutually exclusive
Verify the mime-type in the browser
When someone uploads a file to the input, before sending it, you can run a check. Read the file as a binary and check its magic bytes to see if it really is what it claims to be. Here it is not enough to trust what the browser thinks it is, because it simply maps the extension to a dictionary. Review this answer to see how to use a FileReader object and diagnose the real mime-type .
Verify the mime-type on the server
Depending on which version of PHP you have, the extension FileInfo may be included in the php-common
package % or it would have to be installed using PECL. In either case, this function allows you to verify that the uploaded file is what it claims to be.
For example:
info.php
file whose content is simply <?php phpinfo();
info.jpg
When you receive it with the server, you can do:
$file = $_FILES["file"];
$finfo = finfo_open(FILEINFO_MIME_TYPE);
echo finfo_file($finfo,$file["tmp_name"]);
finfo_close($finfo);
And as much as the person has renamed his file to another extension, that script will tell you that the mime-type is text/x-php
.
Do not run files with other extensions
You can configure your webserver so that the .php
files are passed via fastcgi to the interpreter, while any other type is served as static, if it exists. For example, using nginx
:
# si existe y no es php, se sirve. Si no, error 404
location / {
try_files $uri $uri/ =404;
}
# si es .php esta regla tiene prioridad.
location ~* \.php$ {
fastcgi_pass unix:/run/php/php7.0-fpm.sock;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param SCRIPT_NAME $fastcgi_script_name;
}
With this an attacker who uploads a renamed php will not be able to execute it. At the most you will see the code of the file you just uploaded.
Important
Whether you use validation in the browser or if you are worth of the webserver, in reality these methods do not prevent someone from doing a POST to your backend by skipping the validations. Your input does not allow uploading a file shell.php
but its input yes (you could even do it by altering your form from the console). In other words, it would seem that the most sensible thing to do is to use server-side verification.
Finally, in theory it would be enough if the uploaded files do not have permission to execute, but only read (and maybe write) but this is not bulletproof. If in another part of your site you have a include
that can be manipulated with a parameter of the url, they can execute what they just upload the same.