views:

249

answers:

3

Hi,

I'm developing an ASP.NET Web app and would like the user to be able to either upload an image from their local system, or pass in a URL to an image. The image can either be a JPG or PNG. What security issues should I be concerned about doing this? I've seen various ways of embedding code within JPG files. Are there any methods in C# (or external libraries) which can confirm that a file is a JPG/PNG, otherwise throw an error? At the very least, I'm making the directory which holds uploaded images non-browsable and putting a max size limit of 1mb, but I'd like to implement further checks.

Thanks for any advice.

+2  A: 

Don't let the user determine the file name that will be used on your server. Use [generated guid].jpg instead and put the file name they used in a database table if you need it.

See #12 here: http://www.codinghorror.com/blog/2009/01/top-25-most-dangerous-programming-mistakes.html

External Control of File Name or Path When you use an outsider's input while constructing a filename, the resulting path could point outside of the intended directory. An attacker could combine multiple ".." or similar sequences to cause the operating system to navigate out of the restricted directory. Other file-related attacks are simplified by external control of a filename, such as symbolic link following, which causes your application to read or modify files that the attacker can't access directly. The same applies if your program is running with raised privileges and it accepts filenames as input. Similar rules apply to URLs and allowing an outsider to specify arbitrary URLs.

Be careful with the URL too, make sure it's an absolute, external URL so they can't use your own web server to copy a confidential file off your LAN out into an area they can access it since you'll be loading that URL from code running on your web server.

Hightechrider
Thanks, I'll use a regex to ensure that it's not coming from my domain (or a relative path). The database will hold the link to the image, not the image itself (for those simply submitting url links and not uploading an image)
keyboardP
For uploaded files, I'd recommend storing the Guid you assigned to the file rather than the 'link to the image' (by which I presume you mean the 'UNC path to the image') in the database. That way you can easily adopt a different image storage directory scheme later, for example, subdirectories based on splitting the guid into triplets to avoid having too many files in one directory.
Hightechrider
+2  A: 

This is an absolute minefield. Something to take into consideration (not necessarily an exhaustive list, no guarantees, etc.).

  • Some people use regexs for parsing, so there is no way of knowing if the file contains code. ZIP files have their directory at the end. Sun/Oracle Java PlugIn/WebStart now checks that the file starts with a ZIP local header/entry magic number to avoid "GIFAR" attacks.
  • Serve from a different domain, to avoid same-origin problems.
  • Serve from a different IP address, to avoid same-origin problems.
  • It's a bit tricky to check if the file is exploiting, say, a 0-day buffer overflow. It might even exploit an infinite loop to create a DoS.
  • It's best to re-encode the image.
  • Careful with the URL/file path name. If you give an option, use whitelist checking. In particular NUL characters are "fun". See also directory traversal attacks. In general being able to place a file of given contents an a known location is, at the least, a big dodgy.
  • Or images you might want to check that the size is sane. Decompressing a huge image could well lead to a DoS. Also note that compression algorithms often allow compressing trivial data by huge factors.
Tom Hawtin - tackline
Thanks. At this moment in time, I can only store images on the same server system. However, I'm happy to manipulate the image in anyway before displaying it to the user. Would this mitigate the main problems? Thanks
keyboardP
@TenaciousImpy: In my unqualified opinion: If you're obscure enough, you'll probably get away with reencoding (possibly in a chroot gaol) and being careful with URLs. Note, it is possible to configure a single server with multiple IP addresses (multi-homed) and multiple host/domain names. Probably best not to take my opinion though.
Tom Hawtin - tackline
+2  A: 

Are there any methods in C# (or external libraries) which can confirm that a file is a JPG/PNG, otherwise throw an error?

Maybe, but that doesn't really help in itself. You can easily make file that is both a valid image format and contains active HTML/script content for IE content-sniffing to stumble on. Or then there's the broken Java and Flash origin policies to worry about, which can have the same effect of scripting into your server's security context.

  1. If you process the image (eg. crop, resize) and re-save that makes it very, very difficult to do content-smuggling attacks. However, you should always ensure that your server-side tools are up-to-date, as vulnerabilities in image processing libraries might expose you to server-side exploit.

  2. If you can't do that, your best bet as a mitigation for all content-injection problems is to serve your images from a different [sub]domain which doesn't have access to any of the sensitive credentials (cookies, basic auth) of the main site.

  3. If using a subdomain for this purpose such as images.example.com, your main site should be accessible only through www.example.com and not example.com. Otherwise, content injected into images.example.com can access cookies for example.com in IE. example.com should 301-redirect to www.example.com to prevent unwanted cookie leakage in general.

  4. Add the header X-Content-Type-Options: nosniff to the response to block content-smuggling attacks from IE8. (Doesn't help with earlier versions, alas.)

Also:

  1. Sanitising user-specified filenames is hard, especially if your app is likely running on a Windows server where the rules about usable filenames are complicated indeed. A good place to start is allowing only alphanumerics, and adding your own file extension and prefix. (A prefix is necessary to avoid the Windows reserved filenames, and the empty filename.)

  2. Better: store the user-supplied filename in the database instead of using it as a real filename.

See this question for more discussion of file upload security problems.

bobince
Hi. What would be the best way to process an image? Would it be enough to simply read the image, and save it to my filesystem (with my own naming schema)? Thanks
keyboardP
By ‘process’ I mean loading it into an image processor, doing something to the image and saving it. You'd use `System.Drawing.Bitmap` in .NET. Unfortunately if the image is a JPEG the re-save costs you image quality, so this isn't a good method if you need to preserve the exact original image.
bobince
I think I may go ahead and use a service like Amazon S3 to store the images. I guess this would mitigate most risks? (Especially the fact that there is not involvement of my server with the image files).
keyboardP
Yes. Content injected into that security context would be unable to affect your site. You still have the usual risks of people uploading exploit files to try and hack each others' browsers, but that's not a direct attack against your site (and there's generally not much you can do about it).
bobince
Cool, thanks for the help.
keyboardP