There's three different concerns that get conflated a lot:
- You need to make sure the server can't be tricked into executing code.
- You need to make sure the server can't be tricked into serving a user-uploaded file with a Content-Type (html, svg, xml) that allows Javascript to execute within the site's origin when a user accesses the file.
- Optionally you might want to stop users from accidentally sharing malware by blocking it from being uploaded.
Part 3 is optional. You can imagine the extreme case where you're literally making a website for people to upload malware samples for inspection. In that case, you wouldn't want to implement #3 at all. That server shouldn't do any filtering and shouldn't prevent any files from being uploaded. Files are just bytes; as long as nothing is executing them, they aren't inherently unsafe to store or process. For regular sites, #3 is a nice-to-have, but it should be prioritized after #1 and #2 and can not be done instead of them. Parts #1 and #2 are always necessary.
The main way #1 can be failed is if you're using PHP and you save the files to a directory where PHP is enabled. Then if the user uploads a file with the extension .php
, the server will executes it if the user requests it. You can prevent this by disabling PHP on the directory that uploaded files go into. You could also have an explicit whitelist of extensions which doesn't include .php
. You should test your application by trying to upload a php file that contains some php code (<?php phpinfo();
) and verify that the upload is either blocked, or shows up exactly as you uploaded it.
To solve #2, you need to make sure files are only served with specifically-allowed "Content-Type" headers. Most web servers default to choosing the Content-Type header based on the file extension, so you either need to override that so all files get a safe Content-Type ("application/octet-stream" is a good default that tells the browser to download the file) with maybe a few content types whitelisted (mainly just non-svg images), or make it so there's a whitelist of allowed file extensions. You should test your application by uploading an .html
file and making sure that it does not display as a web page. It needs to be blocked, or prompt your browser to download instead of viewing in-place when you access it.