Santry Technology Solutions, Content Management, DotNetNuke, SharePoint Consulting
Register | Login
Saturday, July 04, 2009

Sections
  
About Us
  
Partners
Downloads
  
 WWWCoder.com Resource Directory

Quick .Net File Download Security
9/4/2003 8:05:03 PM

In this article we will discuss providing a programmable method of securing files on for your ASP.Net applications. This code could come in handy where you have an application hosted on an ISP and you do not have access to a folder outside of your Web directory structure, and you are not able to change permissions on folder in the Web. This method does not require storing your file in a binary field in your database, thus reducing cost of having to buy database storage from your ISP, and with no impact on the network traffic between the database and web servers.

The Problem

On another project we have been talking about how we could allow a person upload a file to the Web application, and be able to secure the file so that someone couldn't type the file URL directly in the browser and be able to download the file.

Several methods were discussed of providing a secure file system for our application:

Database Storage

Storing the file in a database in a binary field, but this method could cost money for folks hosting with an ISP that charges for database storage, and it also impacts network traffic. Basically this solution entails storing the file in the database and attaching some security information in the database about the file; this could be user roles that are allowed to download the file. You can accomplish this by uploading the file to the database; when someone goes to access the file you would authenticate them, check the roles that can access the file, then check the user to see if they have permissions to access the file. Once you're done with the security checks create an ADO stream and send the file information to their client.

The database method meets the requirement of providing secure method of downloading files and prevents someone from being able to access the file directly via typing in the URL into the browser. But as mentioned there are several drawbacks to this method.

File Storage

Another method would be storing the file in a folder on the Web server. If the file were stored in the Web application directory structure you could secure it using NT ACLs. While this method works for an intranet where you have administrative access to the machine, it does not work well if you are hosting a site with an ISP. An ISP may not be able to provide you with the level of security you need for your application.

Another file storage method was storing the files in a folder outside of the Web application's directory structure and streaming the file to the browser. This would be accomplished much in the same way as the database solution, where you could store security information in a table, but the actual file resides on the Web server. You would do your security checks in your code and send the file to the user once they authenticated for access to the file. This method would accomplish restricting the file for downloading directly from typing in the URL of the file since the code is handling the file stream. Again the drawback to this method is you have to rely on an administrator to configure the folders that will reside outside of the Web directory structure.

Another method was to store the file within the directory structure and use the web.config file to restrict access to the directory in the following manner:

<location path="SecureDirectory">
   <system.web>     
      <authorization>
         <deny users="*" />
      </authorization>
     </system.web>
</location>

This method will secure any requests that are being processed by ASP.Net, the problem is it will not secure files that are not being processed by ASP.Net; for example, pdf, doc, xls, and other files you wish to secure. A way around this is to change the settings in IIS so all file extensions are processed by ASP.Net. Again, in the ISP case they may not want to do this because it can have some performance implications.

One Solution

So how do you provide access to files and ensure they cannot be accessed directly by typing in a URL? The following blocks of code will cover one method of doing this using a combination of all the methods described above. This can be done entirely via code.

First, select a location for storing your files. As in the example web.config file mentioned previously, we'll select the "SecureDirectory" folder off of the Web root. We will keep the web.config modification to restrict access to this folder by unauthorized groups. We then create a database table to store security information for our file.

FILE_NAME

ACCESS_ROLES

myfile.doc

admin;managers

This table will contain the names of the files that are uploaded to our secure directory and the security roles that can access the file. Notice the actual file is not stored in the database just the associated security information.

The File Upload Code

Now that you have your table defined to store security information for your file, we need to create methods for uploading and downloading the documents from the server. We will create a webform with a file browse dialog to browse our local system and upload it the server. In your Webform.aspx file add the following:

<INPUT id="cmdBrowse" type="file" runat="server" size="50" NAME="cmdBrowse">
<asp:LinkButton id="cmdUpload" runat="server" Cssclass="CommandButton">
 Upload File
</asp:LinkButton>

Then in our code behind page, Webform.aspx.vb, we need to handle the file upload. The following code will take the file that is being uploaded, save it into our secure directory as defined in the web.config file, and add the extension "resources" to the file so it will secure the file from a directly typed URL. You could use any extension like .vb, .acsx, .config, .resources, .resx or any file type that will be processed by the .Net handler.

Private Sub cmdUpload_Click(ByVal sender As System.Object, _
           ByVal e As System.EventArgs) Handles cmdUpload.Click
     SecureFileUpload()
End Sub
Public Sub SecureFileUpload()
   Dim strFileName As String
   Dim strFileNamePath As String
   strFileName = System.IO.Path.GetFileName(cmdBrowse.PostedFile.FileName)
   'now save the file as an resources file.
   strFileNamePath = Request.MapPath("SecureDirectory") & "\" & strFileName & ".resources"
   If File.Exists(strFileNamePath) Then
      File.Delete(strFileNamePath)
   End If
   cmdBrowse.PostedFile.SaveAs(strFileNamePath)
End Sub

So now if a person tries to go to the file directly by typing in the URL they will be greeted by a login prompt and an eventual 401.2 status message of "Access is denied"


Denied download from directly entering the file URL.

Downloading the File

So now that we have the file on our Web server and it can't be downloaded by browsing to the file URL, how are we supposed to get the file to the people who are supposed to get it?

First, you need to pass the file that you want to download and check it against your database to see if they have permissions on the file. If they have permissions for the file, then proceed with the download. You can write any security check you want, you may want to run a stored procedure to check to see if your user is a member of a certain role for your portal. Since the security mechanism will vary depending on the application, we will call a CheckSecurity method that returns either true or false depending on whether or not the person has access to the file as defined by the table earlier in this article.

If CheckSecurity(filename, userole) Then
   SecureFileDownload(filename)
Else
  'change the http response to access denied or some other error.
End If

After checking the permissions in the database, if the user has access to the file we then call the SecureFileDownload method which accepts the file path as the parameter, maps the file to the physical directory on the server, then sends the download to the client without the resources extension allowing them to download the file.:

Public Sub SecureFileDownload(ByVal inFile As String)
    Dim strFileNamePath As String
    strFileNamePath = Request.MapPath("SecureDirectory") & "\" & inFile
    Dim myFile As FileInfo = New FileInfo(strFileNamePath)
    Response.Clear()
    'now we send the file header minus the resources extension.
    Response.AddHeader("Content-Disposition", "attachment; filename=" & _
         Replace(myFile.Name, ".resources", ""))
    Response.AddHeader("Content-Length", myFile.Length.ToString())
    Response.ContentType = "application/octet-stream"
    Response.WriteFile(myFile.FullName)
    Response.End()
End Sub


Download dialog for the file.

The user will be presented with a download dialog and is now able to save the file to their local system.

As discussed there are several methods you can do to secure your file downloads, the method described in this article is ideally suited for those who do not have access to the administrative functions of the Web server.

By: Patrick Santry, Microsoft MVP (ASP/ASP.NET), MCSE, MCSA, MCP+SB, contributor of "Windows 2003 Server - The Complete Reference", Co-Author of "Administering IIS 5.0" both books published by McGraw-Hill. In addition, Patrick has written several articles and co-authored several books on Microsoft certification. You can view his personal website at http://www.santry.com/.  

 

Related Articles
   Related Document Making Your App Spider Friendly
   Related Document Introduction to Windows and Active Directory Services Interface (ADSI)


Page Options:
format for printing  Format for Printer
email article  Email Page
add to your favorites   Add to Favorites
How would you rate the quality of this content?
Poor - - Excellent
Comments?
Overall Rating:
Comments Left:
Left on 8/29/2008 6:01:37 AM by Anonymous
Comments: awesef
Left on 7/14/2008 5:45:31 AM by Anonymous
Comments: very help ful code
Left on 5/27/2008 7:50:14 AM by Anonymous
Comments: hi am trying to access a file that i have stored outside the application folder.
No ratings available.
Left on 4/29/2008 6:45:00 AM by Anonymous
Comments: Below code working fine in local system and its showing open,save,cancel
Eg:http://localhost/Eg.aspx  working fine opening saveas dialog box

But same example if i run with the IP address its not showing open,save,cancel
just opening the pop up and closing
eg: http;//192.166.1.2/eg1.aspx  its not working fine

Left on 4/29/2008 5:53:56 AM by Anonymous
Comments: Below code working fine in local system and its showing open,save,cancel
Eg:http://localhost/Eg.aspx  working fine opening saveas dialog box

But same example if i run with the IP address its not showing open,save,cancel
just opening the pop up and closing
eg: http;//192.166.1.2/eg1.aspx  its not working fine

From server the excel sheet is not downloading but its working fine in local system.
I have been working since two weeks,Can you help me out on this issue

  FilePath = Server.AMppath(~/"Excel/Activity.xls";)
                    DestFileName = "Activity.xls";
                    Response.Clear();
                    Response.ContentType = "application/ms-excel";
                    Response.AddHeader("Content-Disposition", "attachment;filename=" + DestFileName.Trim());
                    Response.Charset = "";                   
                    Response.TransmitFile(FilePath);
                    Response.End();

No ratings available.
Left on 1/17/2008 2:50:00 AM by Anonymous
Comments: how to check whether download done or cancel
No ratings available.
Left on 12/26/2007 8:59:00 AM by Anonymous
Comments: But when trying to download files from palm it does not for prc files, how to do that
No ratings available.
Left on 12/26/2007 8:57:57 AM by Anonymous
Comments: put when trying to download files from palm it does not for prc files, how to do that
Left on 11/27/2007 12:13:17 AM by Anonymous
Comments: It's very helpfull
with good examples

Thanks,
Vinay Mistry
Left on 11/27/2007 12:13:03 AM by Anonymous
Comments: It's very helpfull
with good examples

Vinay Mistry
Left on 10/16/2007 3:31:00 PM by Anonymous
Comments: Awesome, this is beautiful. Thanks!
Left on 6/6/2007 12:02:04 AM by Anonymous
Comments: Good article.
BTW, another way to protect file from direct URL access is to upload your file into App_Data folder which is protected by default. In this case, you do not need to use .resources extention.
Oleksandr Kovalov. IKO Software
Left on 9/13/2006 11:43:11 AM by Anonymous
Comments: Hi,
In my project it would like to download a file without the save / open dialog box. How can i do that? Please help me. Thanks,
Rathi
Left on 9/13/2006 11:41:53 AM by Anonymous
Comments:
No ratings available.
Left on 8/4/2006 11:49:07 AM by Anonymous
Comments: Actually it does work. The .NET runtime will not allow files with a .resources to be downloaded even if the user types in the exact URL. And if the type in the path without the .resources extension, that file will simply not exist and return a 404 not found error. The only way they'll be able to download the file is via code that you define.
No ratings available.
Left on 8/4/2006 11:34:40 AM by Anonymous
Comments: Nice try but this will not work. If the user's can see the url like www.somewebsite.com/SecureFolder/SecureFile.zip.resources and they are not able to download the file then all they have to do is to remove the .resources and the file will be downloaded.
Left on 8/2/2006 1:09:04 AM by Anonymous
Comments: hi its good,bt my problem is that in table my files path is store and when i want to access that path resepective to my button click
Left on 6/16/2006 9:20:39 AM by Anonymous
Comments: why does download window comes twice on open button click
No ratings available.
Left on 5/10/2006 7:50:54 AM by Anonymous
Comments: I am I am trying to transmit a zip file using the Response.Transmitfile method. Its sending the file and also appending the aspx page's html to it. Hence, when I try to open the file, winzip complains of invalid archive file. I used notepad to view the .zip file and I saw that the binary code file was appended with html code. I deleted the html text file and saved the file and then Winzip was able to open the zip file.

Am I missing anything here? Below is the code I ma using

            Response.ContentType = "application/x-zip-compressed"
            Response.AddHeader("Content-Disposition", "attachment;filename=" + sFileName)
            Response.TransmitFile("C:\test.zip")

I even tried using octet-stream instead of x-zip-compressed. I checked the IIS Server's mime-type and x-zip-compressed has been mapped to .zip file.

Regards
Krish

No ratings available.
Left on 4/4/2006 12:36:13 PM by Anonymous
Comments: This looks to be exactly what I was looking for!
Left on 1/11/2006 2:06:51 PM by Anonymous
Comments: As Mr. Burns would say...
Exxcellllent
Left on 7/22/2005 2:57:09 PM by Anonymous
Comments: Great! Thanks for this article!
No ratings available.
Left on 6/21/2005 3:26:59 AM by Anonymous
Comments: If you use response.transmit the user will be presented with a download dialog abd he/she can able to save the file. incase he/she click on cancel button from the download dialog how to find through the code
No ratings available.
Left on 6/7/2005 5:40:22 AM by Anonymous
Comments: OK banget gitu lho!! Thanks for your article.
Left on 5/12/2005 6:21:33 PM by Anonymous
Comments: Thank you eternally! You have saved my job
Left on 4/19/2005 2:57:08 AM by Anonymous
Comments: very useful
Left on 3/23/2005 2:17:51 PM by Anonymous
Comments: Excellente!
Left on 3/22/2005 2:30:45 AM by Anonymous
Comments: just the perfect code i was looking for
No ratings available.
Left on 2/14/2005 3:17:05 AM by Anonymous
Comments: thank you.
Left on 2/7/2005 1:16:58 PM by Anonymous
Comments: I was wondering how to tackle this problem. Great article!
Left on 1/3/2005 10:14:48 AM by Anonymous
Comments: thanks a lot that´s what I was looking for
Left on 12/22/2004 11:42:26 AM by Anonymous
Comments: This is *exactly* what I was looking for. Thanks!
Left on 12/12/2004 10:37:59 AM by Anonymous
Comments: gandu bahenchod kaha
se a jate hai marake
Left on 11/16/2004 5:33:19 PM by Anonymous
Comments: I need to resolve the "Open" problem (4 post ago).

For some reason, some of my client are aible to open word/application file and some other do encouter problems. Could it be an Internet setting, a problem with office version, ?!?

Regards,

Sébastien slaporte378@hotmail.com
No ratings available.
Left on 11/15/2004 6:05:09 PM by Anonymous
Comments: Very helpful and easy to use.
No ratings available.
Left on 11/10/2004 10:13:48 AM by Anonymous
Comments: very creative, simple is always best
Left on 11/5/2004 8:14:38 AM by Anonymous
Comments: Is there any other way to limit the access to those files? How if user knows the .aspx is fake and type the url without it, will it be downloaded?
No ratings available.
Left on 10/5/2004 5:01:28 AM by Anonymous
Comments: I'm getting the download dialog twice as well. It's very annoying, any ideas on how to avoid it? By the way, it only happens when I click on "Open", "Save" works OK.
No ratings available.
Left on 9/13/2004 6:16:56 PM by Anonymous
Comments: See the new(ish) Response.TransmitFile method for a resource efficient way of streaming a file to the browser.
Left on 8/27/2004 10:01:53 PM by Anonymous
Comments: So can you point me in the direction of an approach that is not a "toy"? I'm seriously interested in the best solution to this problem.
No ratings available.
Left on 8/25/2004 8:39:32 PM by Anonymous
Comments: it is a toy, not suitable for any real applicatiion
Left on 7/29/2004 4:35:14 PM by Anonymous
Comments: Clicking Open instead of Save doesn't work here either.

Also, I've tried using the msdn solution to sending large files (see a few posts down). It works great locally, but when I try it on my live site, I get a 0 byte file. Any ideas?
No ratings available.
Left on 7/4/2004 9:54:00 PM by Anonymous
Comments: Good stuff - am having trouble when downloading and the user selects 'Open'. The file doesn't appear to download correctly? Saving and then Open works fine.
Left on 6/20/2004 9:58:33 AM by Anonymous
Comments: It solved my problem, Thanks alot
Left on 6/18/2004 10:47:41 AM by Anonymous
Comments: What about the open/save dialog popping up twice for the same file when you click on open instead of save.  It's confusing to a user, and it really shouldn't do that...
Left on 6/17/2004 10:12:29 AM by Anonymous
Comments: No, it is a function of the browser, not the code.
No ratings available.
Left on 6/17/2004 10:11:26 AM by Anonymous
Comments: When a user clicks on save, they get a file save dialog.  If they click on "open", they get the same open/save dialog one more time before it actually starts downloading the file.  Is there a work-around, or even better, a way to only present the "save" button?
Left on 6/16/2004 7:20:52 PM by Anonymous
Comments: No they can't, the file would be executed. One change that I will be adding to the article is to use resx instead of aspx, if you're allowing users to upload to your site then you don't want to rename them aspx, or you can have malicious scripts uploaded. Patrick Santry
No ratings available.
Left on 5/8/2004 4:13:15 PM by Anonymous
Comments: if anybody knows that i am using this extention, can he hack my secured files
Left on 3/3/2004 3:06:49 PM by Anonymous
Comments: Microsoft Knowledge Base Article - 812406
No ratings available.
Left on 3/3/2004 3:05:54 PM by Anonymous
Comments: For you folks who want a solution for large file downloads refer to the following KB article: http://support.microsoft.com/default.aspx?scid=kb;en-us;812406&Product=aspnet
In this article you break the response down into smaller chunks.
No ratings available.
Left on 2/6/2004 5:52:20 PM by Anonymous
Comments: This is excellent and simple. Saved me alot of time!!
Left on 2/5/2004 12:45:51 AM by Anonymous
Comments: Just make sure to call the namespace system.io but other than that...awesome, easy example...rock on dude
Left on 1/28/2004 10:44:36 AM by Anonymous
Comments: When you try to download a file with a space in the filename, it doesn't show the extention when downloading it. Anyone knows how to fix this?
No ratings available.
Left on 1/12/2004 9:31:02 PM by Anonymous
Comments: well explained, straightforward example.
Left on 12/10/2003 6:27:09 PM by Anonymous
Comments: The WriteFile(string) method reads the entire file into memory first.  That's a big problem if the file is several hundred MB.  There is also a WriteFile(string filename, bool readIntoMemroy) but that last boolean has no affect - it's a bug! - the file is still read into memory first.

The solution is to read the file bit by bit using the other overloaded method of WriteFile.
Left on 10/20/2003 12:34:33 PM by Anonymous
Comments: It sounds like the problem you're having has to do with permissions. In the directory that you want to be able to upload the file to, make sure the user account that your application runs under has write permissions to the directory. Another thing you can do is do account impersonation in your code, refer the article on Web farm file replication for an example on identity impersonation.
No ratings available.
Left on 10/20/2003 12:29:07 PM by Anonymous
Comments: But I have the opostie problem, I can not upload a .jpg file to my Web directory via my Web program.  When I try to do this, the Web page ask for a user and password Nt user, but I want to upload it without sending any kind of user or password info.  How can I do this? jfarber55@hotmail.com
Left on 10/8/2003 12:19:06 PM by Anonymous
Comments: Response.WriteFile still loads the file entirely into memory.  This article does not address large files, which is what most people are looking for.
Left on 10/4/2003 9:49:27 AM by Anonymous
Comments: I just add a .config to the end of each file since ASP.NET won't serve them to clients. When I user is authorized to download I use an aspx page to stream the file and strip off the .config suffix.
Left on 9/26/2003 12:17:06 AM by Anonymous
Comments: A Good One. Will Really help in securing the documents uploaded.
Left on 9/23/2003 5:04:58 AM by Anonymous
Comments: But when I use Chinese Big-5 Filename, the dialog will not display Chinese filename. It display a random 8-character filename. Why?
Left on 9/20/2003 9:52:15 PM by Anonymous
Comments: Just what I was looking for.
Left on 9/17/2003 10:13:29 AM by Anonymous
Comments: This was exactly the answer to the problem I was trying to solve.  good work!
Left on 9/16/2003 11:47:25 AM by Anonymous
Comments: I hadn't thought about adding the .aspx extension. Cool idea. Easy. Straight forward.
Left on 9/16/2003 8:55:13 AM by Anonymous
Comments: SUPAH
Left on 9/15/2003 3:15:40 PM by Anonymous
Comments: how about a function to return the correct content-type based on the file extension?  in this example, pdfs and htms will be downloaded
No ratings available.
  

 Latest Articles
  

 Latest News
  

 

Spotlight
Syndication

 


 


Digg This
 


DotNetNuke Platinum Benefactor

  
 

 Terms Of Use | Privacy Statement
 Copyright 2008 - Santry Technology Solutions, Box 172, Girard, PA 16417, (814) 774-0970