43

I have a website that shows galleries. Users can upload their own content from the web (by entering a URL) or by uploading a picture from their computer.

I am storing the URL in the database which works fine for the first use case but I need to figure out where to store the actual images if a user does a upload from their computer.

Is there any recommendation here or best practice on where I should store these?

Should I save them in the appdata or content folders? Should they not be stored with the website at all because it's user content?

Flexo
  • 87,323
  • 22
  • 191
  • 272
leora
  • 188,729
  • 360
  • 878
  • 1,366

5 Answers5

67

You should NOT store the user uploads anywhere they can be directly accessed by a known URL within your site structure. This is a security risk as users could upload .htm file and .js files. Even a file with the correct extension can contain malicious code that can be executed in the context of your site by an authenticated user allowing server-side or client-side attacks.

See for example http://www.acunetix.com/websitesecurity/upload-forms-threat.htm and What security issues appear when users can upload their own files? which mention some of the issues you need to be aware of before you allow users to upload files and then present them for download within your site.

  1. Don't put the files within your normal web site directory structure

  2. Don't use the original file name the user gave you. You can add a content disposition header with the original file name so they can download it again as the same file name but the path and file name on the server shouldn't be something the user can influence.

  3. Don't trust image files - resize them and offer only the resized version for subsequent download

  4. Don't trust mime types or file extensions, open the file and manipulate it to make sure it's what it claims to be.

  5. Limit the upload size and time.

Community
  • 1
  • 1
Ian Mercer
  • 38,490
  • 8
  • 97
  • 133
  • 2
    Would love a bit more detail on #3 and #4. Does the resizing ensure that they're actually images? And by `open it` do you mean to check the first bytes that are supposed to tell you the type of file? – Omar Dec 27 '10 at 08:51
  • 3
    3. essentially removes the possibility that corrupt metadata has been included in the image file to attack some poorly written browser or other image software. 4. Yes, check that it really is an image file with the appropriate image metadata corresponding to the type that it claims to be. Can you load it into a bitmap, etc.? Users will often upload corrupt images to your site, rejecting them early is a good idea. – Ian Mercer Dec 27 '10 at 20:56
  • 3
    you mention "dont put the files within your normal web site directory structure. But if i don't do that, how can i link to this content ?? – leora Jan 30 '11 at 19:10
  • @ooo Create an action method that returns a `FileResult`. The action takes the [unique, unguessable] identifier you assigned on upload, e.g. a Guid and returns the image file. – Ian Mercer Feb 01 '11 at 15:22
  • @Hightechrider - thanks for your response. Can you give a recommended location? the appdata folder ?? or are you saying anywhere but a visible URL in the website structure – leora Aug 26 '11 at 16:54
  • @Hightechrider - any feedback on the question in my last post ? – leora Aug 30 '11 at 06:22
  • 2
    Yes, anywhere that's not visible. Uploads normally get to be large so mostly I put them on a separate drive/SAN/... push them to S3/... – Ian Mercer Sep 08 '11 at 23:04
  • 2
    If you are on a hosted solution, you could put in a folder in site structure but deny all access: – Paul Tyng Oct 11 '11 at 19:38
9

Depending on the resources you have to implement something like this, it is extremely beneficial to store all this stuff in Amazon S3.

Once you get the upload you simply push it over to Amazon and pop the URL in your database as you're doing with the other images. As mentioned above it would probably be wise to open up the image and resize it before sending it over. This both checks it is actually an image and makes sure you don't accidentally present a full camera resolution image to an end user.

Doing this now will make it much, much easier if you ever have to migrate/failover your site and don't want to sync gigabytes of image assets.

dmnc
  • 791
  • 7
  • 14
  • I like this answer but you should also consider security. Using S3 will minimize the ammount of traffic going through your site. But wou want to ensure that the file are what they say they are, I would apply a filter to the image prior to uploading to s3, that way you know its an image is the filter succeeds. – Angelom Oct 18 '11 at 07:57
  • Indeed. That was sort of what I was getting at with the resize step but either way, it's a good idea to have any sort of good solid check that you do have a real image. – dmnc Oct 19 '11 at 08:53
4

One way is to store the image in a database table with a varbinary field.

Another way would be to store the image in the App_Data folder, and create a subfolder for each user (~/App_Data/[userid]/myImage.png).

For both approaches you'd need to create a separate action method that makes it possible to access the images.

Trax72
  • 958
  • 5
  • 12
  • We have the database method for static common content on web sites. We use it to call versions. This works well, and we can compress the binary blob. – Omnia9 Oct 13 '11 at 02:28
3

While uploading images you need to verify the content of the file before uploading it. The file extension method is not trustable.

Use magic number method to verify the file content which will be an easy way.

See the stackoverflow post and see the list of magic numbers

One way of saving the file is converting it to binary format and save in our database and next method is using App_Data folder.

The storage option is based on your requirement. See this post also

Set upload limit by setting maxRequestLength property to Web.Config like this, where the size of file is specified in KB

<httpRuntime maxRequestLength="51200" executionTimeout="3600" />
Community
  • 1
  • 1
Prasanth
  • 3,029
  • 31
  • 44
-2

You can save your trusted data just in parallel of htdocs/www folder so that any user can not access that folder. Also you can add .htaccess authentication on your trusted data (for .htaccess you should kept your .htpasswd file in parallel of htdocs/www folder) if you are using apache.

Flexo
  • 87,323
  • 22
  • 191
  • 272
Sanjay dev
  • 435
  • 1
  • 4
  • 11