Security is one of the most important aspect of a website. Strong security can guarantee the protection of confidential data of the users. ASP.NET allows us to easily enable the folder and file level security by writing few lines of code in web.config. The ASP.NET security can protect all the files that are mapped as secured files. These files include .ASPX, .CONFIG, .RESOURCES and .CS files. You can also add custom file mappings for your files by using the IIS manager. Since, .PDF and .ZIP files are not included in those mappings user can always download these files using the absolute URL. Some of the ISP allows you to add your own file mappings which allows you to secure your custom files. However, if your ISP does not provide that feature then you can use some of the methods illustrated in this article.
Introduction:
Security is one of the most important aspect of a website. Strong security can guarantee the protection of confidential data of the users. ASP.NET allows us to easily enable the folder and file level security by writing few lines of code in web.config. The ASP.NET security can protect all the files that are mapped as secured files. These files include .ASPX, .CONFIG, .RESOURCES and .CS files. You can also add custom file mappings for your files by using the IIS manager. Since, .PDF and .ZIP files are not included in those mappings user can always download these files using the absolute URL. Some of the ISP allows you to add your own file mappings which allows you to secure your custom files. However, if your ISP does not provide that feature then you can use some of the methods illustrated in this article.
Using Custom HttpHandler:
The first approach makes use of the custom HttpHandler to secure the files. The HttpHandler handles all the requests of the files which ends with .zip extension. Once, the request is handled by the HttpHandler it checks and makes sure that the user is authenticated. If the user is not authenticated then he is redirected to the error page. If he is authenticated then he is presented with the file download dialog box. Let's take a look at the HttpHandler implementation.
using System;
using System.Data; using System.Configuration; using System.Web; using System.Web.Security; using System.Web.UI; using System.Web.UI.WebControls; using System.Web.UI.WebControls.WebParts; using System.Web.UI.HtmlControls; public class ZipFileHandler : IHttpHandler { public ZipFileHandler() { } public bool IsReusable { get { return false; } } public void ProcessRequest(HttpContext context) { if (!context.User.Identity.IsAuthenticated) { context.Response.Redirect("~/ErrorPage.aspx"); } // else download the file DownloadManager.DownloadFile(context.Request.CurrentExecutionFilePath); } } |
The DownloadManager class is responsible for streaming the file to the client. Let's take a look at the DownloadManager.DownloadFile method.
public static void DownloadFile(string url)
{ string fileName = String.Empty; string filePath = String.Empty; if (!String.IsNullOrEmpty(url)) { filePath = HttpContext.Current.Server.MapPath(url); fileName = System.IO.Path.GetFileName(filePath); HttpContext.Current.Response.ClearContent(); HttpContext.Current.Response.ClearHeaders(); HttpContext.Current.Response.AddHeader("Content-Disposition", "inline; filename=" + fileName); HttpContext.Current.Response.ContentType = "application/zip"; HttpContext.Current.Response.WriteFile(filePath); HttpContext.Current.Response.End(); } } |
The DownloadFile method accepts the URL of the file as an input parameter. After clearing the response content and headers the file is simply written to the output stream using the Response.WriteFile method. As soon as the WriteFile method is executed the file download box will pop up on the screen which will allow you to download the requested file.
There is one problem with using the Response.WriteFile which is that it cannot be used to download a large file. If you try to download a large file you will receive server not found error.
So, the question is that how can you download large size files. There are couple of ways of handling this problem. The first one is to send the file in small chunks so that the buffer is not overloaded. Below you can see the complete code for the method DownloadFileInChunks which is taken from the MSDN (read original here).
public static void DownloadFileInChunks(string url)
{ System.IO.Stream iStream = null; // Buffer to read 10K bytes in chunk: byte[] buffer = new Byte[10000]; // Length of the file: int length; // Total bytes to read: long dataToRead; // Identify the file to download including its path. string filepath = HttpContext.Current.Server.MapPath(url); // Identify the file name. string filename = System.IO.Path.GetFileName(filepath); try { // Open the file. iStream = new System.IO.FileStream(filepath, System.IO.FileMode.Open, System.IO.FileAccess.Read, System.IO.FileShare.Read);
// Total bytes to read: dataToRead = iStream.Length; HttpContext.Current.Response.ContentType = "application/octet-stream"; HttpContext.Current.Response.AddHeader("Content-Disposition", "attachment; filename=" + filename); // Read the bytes. while (dataToRead > 0) { // Verify that the client is connected. if (HttpContext.Current.Response.IsClientConnected) { // Read the data in buffer. length = iStream.Read(buffer, 0, 10000); // Write the data to the current output stream. HttpContext.Current.Response.OutputStream.Write(buffer, 0, length); // Flush the data to the HTML output. HttpContext.Current.Response.Flush(); buffer = new Byte[10000]; dataToRead = dataToRead - length; } else { //prevent infinite loop if user disconnects dataToRead = -1; } } } catch (Exception ex) { // Trap the error, if any. HttpContext.Current.Response.Write("Error : " + ex.Message); } finally { if (iStream != null) { //Close the file. iStream.Close(); } } } |
Another way to download a large file is to use the Response.TransmitFile method. Response.TransmitFile allows you to send the file in small chunks and does not saves the file in the memory thus allowing you to download massive files. Take a look at the code below which uses Response.TransmitFile to download a zip file.
public static void TransmitFile(string url)
{ string fileName = String.Empty; string filePath = String.Empty;
if (!String.IsNullOrEmpty(url)) { filePath = HttpContext.Current.Server.MapPath(url); fileName = System.IO.Path.GetFileName(filePath); HttpContext.Current.Response.ClearContent(); HttpContext.Current.Response.ClearHeaders(); HttpContext.Current.Response.AddHeader("Content-Disposition", "inline; filename=" + fileName); HttpContext.Current.Response.ContentType = "application/zip"; HttpContext.Current.Response.TransmitFile(filePath); HttpContext.Current.Response.End(); } } |
Tips for Downloading Files:
Conclusion:
In this article you learned few ways that you can use to secure and download the files. I hope you enjoyed this article, happy coding!