Skip to content

Latest commit

History

History
59 lines (53 loc) 路 5.8 KB

FILE_UPLOAD.md

File metadata and controls

59 lines (53 loc) 路 5.8 KB

File upload security and good practices checklist

If you're planning to implement a file upload system in your platform, it's crucial to ensure that the process is secure and won't expose your project to potential security exploits. Below is a comprehensive checklist to help you implement a minimally protected file upload feature:

  • Check the uploaded file:

    • Check if the authentified user is allowed to upload a file
    • Check if the authentified user uploading a file is not a bot (essentially by Recaptcha v3 methods or others)
    • You must check if the file is valid before storing it server side :
      • Check if the size is acceptable to avoid Denial of Service (DoS) attack
      • Don't rely solely on the file extension, but also check the mime type as well.
        • Check if the mime type is acceptable
        • Avoid uploading php files (check the filename/mimetype turned to lowercase) to avoid Remote Code Execution (RCE) exploits. It also includes extensions like php1, php2, php3, php4, php5, php6, phtml....
        • Check the filename to avoid Path Traversal exploits (the filename must not be named like a path).
        • Avoid using the content-header to determine file type, as it can be manipulated by attackers (the headers are never safe).
        • Sanitize filenames by avoid special characters such as %, ;, :, >, <, /, \, ., * to protect your project from Null Byte injection, Path Traversal and various others attacks.
        • When uploading a svg or any XML file, parse it correctly to avoid XXE or XSS attacks (in the case of svg files)
        • When checking the filename, be careful about the obfuscated file extensions (like exploit.png.sh or exploit.jpeg.php)
      • Check if the file is not a malware using an antivirus library:
      • If the uploaded file is a picture, and you don't want it to be animated, know that GIF files are not the only one to be animated, APNG files are animated too.
    • Feel free to use a third party library that manage your upload feature, but be sure that you also check if everything is correct in your side:
  • Rename the uploaded file:

    • Your file has been renamed server side with a random string (uuid or random string of at least 16 characters), to prevent filename guessing attacks.
    • The data of your file is stored in your database, with data like:
      • id (not sequential)
      • original filename
      • new filename
      • uploaded date
      • mime type (only if the file is not encrypted)
      • file size
      • ... other informations necessary to make your platform functional
    • Do not store the base64 in your database.
  • Choose your destination wisefully:

    • Create multiple folders in a uploads (or a different name) repertory. But be sure it won't be guessable, so avoid using sequential folder name to prevent unauthorized access.
    • Store the uploaded files in a non-public folder to prevent unauthorized access.
    • Alternatively, consider using a CDN to store your files securely.
  • File access:

    • According to the data in the database, only some users may be able to access a specific uploaded file. Make sure that the route that is returning your file have a good middleware and strong verifications.
    • Avoid writing the path or the filename inside the route returning the file, but use a unique identifier from the database to fetch the file. For example:
    id filename original_filename uploaded_date mime_type
    e7092b88-bda0-49e1-a700-47c64942b5ef d6485Jbfdlk8721c3x83x.png image.png 2023-10-10 image/png
    • Good: http://api.website.com/files/{user_id_or_any_other_id_or_hash}/e7092b88-bda0-49e1-a700-47c64942b5ef
    • Bad:
      • http://api.website.com/images/d6485Jbfdlk8721c3x83x.png
      • http://api.website.com/images/d6485Jbfdlk8721c3x83x
      • http://api.website.com/images/image.png
      • http://api.website.com/path?=images/image.png
  • Bonus:

    • Consider encrypting your files using symmetrical or asymmetrical algorithms (such as AES256 or RSA2048). ENCODING IS NOT ENCRYPTING !
    • Implement disk usage quotas for each user with a filesize data field in your database to prevent users from uploading multiple excessively large files.
    • Be careful of what your users upload in YOUR server.