Quick .Net File Download Security

Quick .Net File Download Security
http://www.wwwcoder.com/main/Default.aspx?tabid=68&mid=407&site=1795
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.

你可能感兴趣的:(Quick .Net File Download Security)