Uploading files to my site - asp.net

I have an ASP.NET application. I want users to be able to upload documents. Where in the file system should I store those documents? Users should be able to upload them and see the hyperlinks to them on the site, but UserA should not be able to see UserB's documents, but the administrator role should be able to see all of them.
I'm assuming I don't want to upload them to a folder with my web application because then the web server can serve them up directly. I don't want to store the file in the database, but I can store file paths in the database.
Somebody please give me some best practices. Thanks!

Depending on the size of the files, one options would be to store the files outside the web root so no one could hot-link to them, then, as has been suggested, produce a page that takes some arguments and Response.WriteFile() from said directory.
If the files are large you might want to use Response.TransmitFile to save on some memory on the server.
From an implemenetation point of view, I would probably store the real name of the file in the database to avoid naming collisions and save the files on disk renamed to something like a GUID or just an integer ID taken from the database table.
Then when you write the file to the output stream you can use a content disposition header to rename the file back to the original name.
HTH!

You probably want a folder structure with one folder per user. You could write your own CreateFolder() method that after creating the folder adds a web.config file with authorization rules, letting only the user and administrators access it. That way, users can only access their own files, but admins can access all.
EDIT: For clarification - I am assuming that you are using the ASP.NET Membership features (although not necessarily exactly as is), which lets you put individual web.config files in a directory with the nodes shown below to control access.
<configuration>
<system.web>
<authorization>
<allow roles="admin" />
<allow users="TomasLycken" />
<deny users="*" />
</authorization>
</system.web>
</configuration>

Another way of doing it, is to place all the files in one place, to which you statically allow no access to anyone, and then have a generic handler (.ashx) which serves the files after looking up url and permissions from the database. This is probably a cleaner approach, and it will also take less space seeing as you won't have tons of web.config files laying around...
Note: I purposely posted this as a separate answer, so you can mark the solution you prefer as your answer and ignore the other one.

You can create a virtual directory adjacent (as a sibling) to the root of your website in IIS this does a couple of things 1) it prevents users from accessing the files directly by guessing the file location, 2) you can point the virtual directory to any location you wish, 3) with directory browsing turned off you can prevent anyone from seeing the structure. You can then store the paths in a database further removing the actual structure from the clients.

I have implemented solution like this. I store files in the protected (via web.config section) folder within the website, but instead of real file names I used guids. I also had a database that mapped guids to real names and had some extra information like file size, type etc. In your case this information could also contain name of the user that uploaded the file.
To download the file I implemented HTTP handler that would get a guid parameter and based on the file type set appropriate HTTP header and write the content of the file into response. Before I write file to the response I also check permissions for the current user. Then I have a page that render a list of file names as hyperlinks that point to this HTTP handler with guid parameter that correspond to particular file in the protected folder.
For upload I used very nice SlickUpload control:
http://krystalware.com/Products/SlickUpload/

Related

Prevent Direct Access To files ASP Web.Config

Strange question but hopefully its possible.
we have files in the root of our site (/files) these are uploaded through the main cms side of the website (/admin) and to be accessed by people who have access to the (/school) directory.
At the moment, if you have the direct link URL EDIT TO THE FILE you can gain access to the file
the files folder has its own web.config file with some rules, is there a way i can add some of my own authentication within the web.config to only allow requests that come from the School folder to have access to the files?
In my head i would have a piece of VB code that does something like this:
If (Request.UrlReferrer <> Nothing) Then
If Page.Request.UrlReferrer.ToString.Contains("/School/") = True Then
???
End If
Else
Response.Redirect("index.aspx")
End If
I've tested this in a simple page and it seems to work okay.
Well, I would assume that the users who can use school folder are memembers of a secuirty role called School (or some such).
thus, any user not a member of school can't use the pages (or files) in the school folder.
Since you want the SAME restricitons for the folder files, then use the same web.config to secure the files folder.
That will mean only users who can use the shools folders will also be the same group of people that only use the files folder.
Now the above will not stop members of securty role "school" from typing in any valid URL to the files folder. So, if you want to prevent this, then I would suggest that for all files up-loaded, you create a folder inside of files folder based on their PK row in the membership table (Memebership.ProviderKey).
Then what you would do is turn off all role groups rights to the files folder. I perfer not EVER allowing a direct URL to files.
Remember, only IIS respects the IIS security settings and provider for a web based URL. Code behind is 100% free to load, read, write, use, play with ANY file via code behind. Code behind uses plain jane FULL path names - and those path names and file names used by code behind does NOT care nor use IIS security settings. Only web based URL's dish out by IIS respect and use the IIS security settings you have for the schools folder. So, copy the web.config for schools over to files, and you are done.
But, code behind? it does not care nor use those settings at all.
So, code behind does NOT use nor respect nor care about IIS security settings. IIS role membership ONLY applies to the asp.net pages and web based URL's. But, code behind is a 100% free to get and grab any file on the system - even files outside of the wwwroot path name of the web site.
So, as a 2nd level and better security?
I would not allow ANY URL's to the files folder.
You then display a grid or list of files on the web page, and code behind for the download button can then go read/get the file (you can use TransMitFile to download that file)
So, best approach is to not allow ANY valid URL's to the files folder.
However, for now, since you only want people who can use the schools folder also be the SAME people that can use the files folder? Then just use the same web.config for both folders - only those people with role of "school" will thus have use and rights to the files folder.
From the information you provided, then you don't really need any code changes - only to take the security settings from the school folder web.config, and copy that to the files folder, and you should be done.
Now, it is possible that the schools folder is not secured by using IIS security and roles - but then again, that would a epic face plant and horrible design choice.

Path traversal vulnerability

The concept of path traversal is new to me need some guidance please.
In my project I have following line of code:
uploadimg.SaveAs(Server.MapPath("tempfiles/" + fUIName));
FileUpload1.SaveAs(Server.MapPath("tempfiles/" + fSIName));
Is this code is vulnerable to PathTraversal vulnerability.
Can any one help me understanding the concept of path traversal and how to remove/avoid it.
Thanks!
Edit 1:
It is also mentioned that I am storing files in tempfiles folder temporary. After the purpose of saving the file fulfilled I am deleting the files from tempfiles. So can I skip this vulnerability?
Please guide.
Thanks!
The path traversal is means that some one upload a file to your site and can access it direct from the URL (if he knows the path, or can find it from some other page).
Eg, lets say that you upload a pdf file named file.pdf at tempfiles/
Then you probably show it on some page as http://example.com/tempfiles/file.pdf
Now the attacker knows where the file is uploaded, and then its upload to you some other file, maybe an html with fraud, maybe some server browser in an aspx page etc... and direct call it from the url.
Solutions
You can upload all the files to a secure folder like App_Data that you can not direct access it.
You can upload it to a folder that you change the permissions and again you can not direct access it. (see here how you can do that How to set correct file permissions for ASP.NET on IIS)
You can limit the extensions for what you upload and let only images for example, and put that on that directory to avoid anyone to run anything there.
<configuration>
<system.web>
<authorization>
<deny users="*" />
</authorization>
</system.web>
</configuration>
Now, if you upload pdf to a directory that the user can not access direct from the url, you need to create a handler that return the uploaded files. The handler must knows if the user is allowed to view the file, if the file is safe, if the file come direct from the site.
some simple examples.
file download by calling .ashx page and Alternate image display in asp.net
And one last solution is to check the reference and make sure that is comming from your site and its not a direct call from the url using this HttpContext.Current.Request.UrlReferrer.Host. Meaning that the user is uploading an image, but its allowed to view it only if its come the request from a page of your site using some link.

Web-enabled file storage and security implications of giving delete permission to IIS_IUSRS

I've had this question for many years, and did research every time that this issue arose, but could never find a definite answer. Somehow the mighty Internet, MSDN, community forums, are either silent or vague on this. Out of thousands of development-related uncertainties, this is the only one that remained elusive.
To the point: in order to enable users to upload and manage images (and other files) used in their blog posts, in a shared hosting environment, I can either consider SQL Server binary data types (performance implications), or the file system. To use the latter, the necessary permissions need to be set for the IIS_IUSRS role on the storage directory : create/write, read and delete. My question - if I do this, what are the security implications? Could someone somehow take advantage of this, bypass the ASP.NET request pipeline and manipulate the files inside the folder without making a request to the corresponding ASP.NET handler (which checks rights, validates uploads, etc.)?
I've developed several systems that allowed file uploads and this has always bothered me. Now, hopefully, someone will be able to put my mind at ease and, ideally, explain the mechanics behind the process.
UPDATE
After viewing the latest answers (many thanks), another formulation of the question:
Is it in any way possible for a client to somehow bypass the request pipeline and create/delete files inside a directory that allows it (assuming the person knows the directory structure)? Or only the code that handles the request can do it? Any potential exploits?
The main problem is to been able to upload a script, an aspx page, in this directory with the photo files, and runs it.
Here is one case: I've been hacked. Evil aspx file uploaded called AspxSpy. They're still trying. Help me trap them‼
The solution to that is to add this extra web.config file on the directories that allow to upload files and not permit to run any aspx page. Also double check to allow only extensions that you permit and not allow to change that on the file name, if they have the opportunity to make rename.
<configuration>
<system.web>
<authorization>
<deny users="*" />
</authorization>
</system.web>
</configuration>
Also on the directories that you allow to upload files, do not permit to run any other script like simple asp, or php or exe, or anything.
general speaking
All your pages have permissions to run and manipulate many things on the server. What you give now is the ability of write on some directories, also by using some aspx page. The asp.net now have one more extra permission to write files there, on the photo folder. Also note here, that you asp.net page have this control, not the user. What you do there with your code can write on this directories, so must be carefuller there to double check where you write and not allow any other directories, not allow the user to manipulate the directory that can be written to.
So this is the weak link. To been able to upload more script that can take control of the server, at least the part that can be access by the asp.net user of this pool.
Having done this before, I'd make two recommendations:
First, do not store the uploaded files in the same directory structure as your application code (if possible). Make it a well-defined external location, and locked down explicitly to only the user the application is running as. This makes it harder for a malicious upload to be injected into your application as nothing in the web server, or ASP.NET itself, knows how to access the file (only your application).
If that is absolutely not possible to do so, be sure to make sure no external user can access the storage folder using standard ASP.NET authorization and only allow writes by your application user to this folder, nothing else.
Second, do not store the uploaded files with their original names and file extensions; Keep that meta-data separate. Just consider the file a raw binary blob of data. This is good for a couple reasons. First, it prevents inadvertent execution of the file on the server, be it by someone accessing the file system directly, the web server, or ASP.NET. Second, it makes it much more difficult for an attacker to exploit a malicious upload as they should never be able to guess the name, or path, of the file on the server.

Securing Individual Files in ASP.NET

I have a scenario where a user will have access to a one-time-url.
When the user clicks on the URL, specific files will be available to that user.
I have many files on the site but would only like certain files to be accessible by that user.
I have though about generating an authenticated cookie and using forms based auth and applying permissions to a certain folder, but I need authorization on indiviual files. and the files will constintly be changing.
What would be the best way to give a user only access to specific files? (I won't display the other files, but I still do not want other files available if they are typed in the URL)
I would create an .ashx (handler file) and have that serve the files to the user (load into memory and then write the contents out by pushing the file to the content stream). That way the end user never has permissions to the actual files on the system but can still access them. Your code can then control when and how long each file is available to a user.
I would provide an abstraction around the actual file retrieval. That way the user never sees file name. Something like www.example.com/File.aspx?id=SOMERANDOMGUID
That RANDOMGUID could reference a file in the back end.
If you have lots of disk space, one way to accomplish this is to copy the files to a randomly-generated folder, so that the URL to a user's files is unique for each user.
I think it would be easier if your files are associated with an ID and the path is kept in the database. This way you can pull the files using the ID.

URL-authorization and non-Asp.Net related file types

URL authorization only applies to Asp.Net related file types?1 But why couldn’t it also be applied to non-Asp.Net file types?
Thanx
This is because of the script maps for ASP.NET. Only certain extensions are mapped into ASP.NET. The rest are handled directly by IIS. This is by design, for performance reasons.
There are two ways to handle this.
Duplicate your authorization rules in the web.config files in NTFS File ACLs (that is, set permissions on folders and files directly). Make sure that the user's authentication scheme matches the accounts and groups used for controlling access... in other words, if you're using SQL to store username tokens, this won't work, because those tokens won't necessarily map back to domain users and groups/roles.
Create an IHttpHandler to serve up your non-ASP.NET files. From the ProcessRequest method, call the Server.MapPath(url) method on the incoming URL, then stream out the file using Response.WriteFile(filename). You will probably need to set the ContentType property first. And, (here's the bad news), you may still need to perform a declarative or imperative access check -- just having the entries in the web.config files may not work. See Custom ASP.NET Processing with HTTP for more information on writing your own handler. It's probably a good idea to make separate handlers for each content type. Once you've written one, you'll see how easy they are to make.
You could try (haven't tried this myself) to add <httpHandlers> elements to web.config files where you have additional <authorization> elements -- use the <remove> element to remove the inherited HttpHandler and add another one at the subfolder level (perhaps pointing back to the same class?). I'm not sure this will work, but it's worth a try.
Finally, if you really don't want to go through and do all this work, you could simply add more extension mappings in IIS. For example, take a look at How to: Register HTTP Handlers, you can add a mapping for .jpg files to the aspnet_isapi.dll (take a look at the existing mappings for .aspx and so on). You do not need to add an HttpHandler element to your web.config, because the machine level web.config already contains this entry:
<add path="*" verb="GET,HEAD,POST" type="System.Web.DefaultHttpHandler" validate="true"/>
Please note that this may have very serious performance issues on your site.

Resources