Hacker News new | ask | show | jobs
by mr_puzzled 2770 days ago
Somewhat related : are there any guides/tutorials about how to do secure file uploads in webapps and how to avoid obvious security pitfalls?

Reading the Django docs https://docs.djangoproject.com/en/2.1/topics/security/#user-... , specifically,

>Django’s media upload handling poses some vulnerabilities when that media is served in ways that do not follow security best practices. Specifically, an HTML file can be uploaded as an image if that file contains a valid PNG header followed by malicious HTML. This file will pass verification of the library that Django uses for ImageField image processing (Pillow). When this file is subsequently displayed to a user, it may be displayed as HTML depending on the type and configuration of your web server.

is a little concerning. They recommend serving images from a different domain and whitelist file types. Is that enough? Anything else needs to be done to improve security? Does handling uploads alone give attackers an RCE oppurtunity or is it safe to handle files in the server and then upload to aws s3?

3 comments

Some (but probably not an exhaustive list) of pitfalls:

    * Filename: Either force random data or only allow a whitelist through.  Do not trust unknown character ranges.
    * File-existence: Never over-write files, resumed uploads should be handled VERY carefully (it's easier to just not).
    * File-extension: (I) do not care; security design should never trust this data anyway.
    * File-size: You don't have control of this on the host?
    * Disk space: It might be a good idea to reserve at least some of this, or set a maximum ingress pool size.
Thanks for that, great read.

I think for my use case going with s3 will be easier and better for security. So how do I actually do it? Let users directly upload to s3 and have a lambda function call my server to store the url? If the image file is maliciously crafted, how does using s3 help, especially when serving the content? How can I set the headers when serving images from s3? And is there a way to identify that a specific user uploaded this file, so that I can have rate limiting? Is it possible to generate a signature or something to identify a user that I can decode server side to say "ok, this user uploaded the file and he is who he says he is". Maybe sign using the cookie that django sets for each user?

There is a few options, such as using AWS Cognito, or signed requests. I personally use signed requests which allows you to specify where and what type of files are allowed to be uploaded. First the user asks my server for a policy and signature, then uploads directly to S3, then sends another request to my server when done. My server will then verify and process uploaded files.

Likewise requests can also be signed so you can implement rate limiting on you side, and just allow S3 to serve the payload. Or you can do thing like use Cloudfront to server the objects which can use various methods of authentication such as signed cookies, or Lambda functions.

Headers can be set in the S3 object metadata.

Thanks for the explanation. Follow up question : how did you implement the signed cookies part?
Use the the aws sdk to generate credentials on your server, pass the returned creds to your frontend. The request to generate the credentials allows you to lock down the size and type of file. They can go directly into a form or used in javascript. Lot of github libs and stack overflows that go into more detail. https://docs.aws.amazon.com/AmazonS3/latest/API/sigv4-UsingH...
On your server, send "X-Content-Type: nosniff" and make sure the right Content-Type is returned by the server. This will prevent browsers to load an image file (Content-Type: image/png) as anything else than an image.