In a previous post (http://aspadvice.com/blogs/rjdudley/archive/2005/05/21/2595.aspx), I showed one way to protect files from direct download by configuring IIS.  In a shared hosting environment, this usually isn't possible, so I'll show another way to protect these files.

First, a little review.  Out of the box, only certain file types are mapped to the ASP.NET ISAPI filter.  These include .aspx, .ascx, .ashx, etc.  If these pages are requested, IIS hands off processing to the ASP.NET filter.  Otherwise, IIS serves the file directly (or hands it off to another ISAPI, as necessary).  There are also a number of file types mapped to ASP.NET that are protected by the HttpForbiddenHandler.  This is an HTTP Handler that prevents direct download of files of the specified type.  If you examine the <httpHandler> section of your machine.config file, you'll see the list.

It would seem that simply adding a file extension to the <httpHandler> section and have the HttpForbiddenHandler prevent its download would be great, but unfortunately, you need to also configure IIS for any new extention you want handled, which is the problem in the first place.

However, there's a little trick we can use.  Let's say you have a file named "protected.pdf" which you wish to prevent direct download of.  You can rename this file to "protected.pdf.resources", and since the .resources extension is already forbidden, users will not be able to download this file directly even if they can guess the file name.  Try it and see.

When it comes time to allow users to download the file, you can use the System.Web.HttpResponse.WriteFile method to send the file to the user.  You may have to clear the response and add a content type to make this all work correctly, as shown:

                strFileName = Server.MapPath("protected.pdf.resources")

                strFileId = StrFileName.ToString.Replace(".resources", "")

                With HttpContext.Current.Response

                    .ClearContent()

                    .ClearHeaders()

                    .ContentType = "application/pdf"

                    .AddHeader("Content-Disposition", "inline; filename=" & strFileId)

                    .WriteFile(strFileName)

                    .End()

                End With

<update 2006-06-06>

Another way to protect files in a shared hosting environment is to place them outside of the URL-addressable folder, and use the Response.Writefile() method to send them to the browser.  A number of hosts configure web applications so that a parent directory can be accessed via FTP, and the URL points to a child directory of this parent.  If you access your site via FTP, and then have to drill down into a 'wwwroot' (or somesuch name) folder, your site is configured this way.  You can create another child directory of your FTP root, place your files in this new directory, and pass in the path (may take a little experimentation to get the exact path) and filename to the response.writefile.

Sponsor