Streaming Files for more Secure Downloads in ASP.NET

If you just have a link to a file on your web site then you maybe leaving yourself open to other sites linking to the same files thereby giving their users the benefit of content without any hit on their bandwidth. It will also give clues to your site structure that can only be of benefit to anyone wishing to compromise your site’s security.

One workaround to this is to stream the files to your users using a FileStream and the Response object. Here is some C# code that will do that job for you:

/// <summary>
/// Write a secure file out to the response stream. Writes piece-meal in 4K chunks to
/// help prevent problems with large files.
/// <example>
/// <code>WriteFileToResponse(@"secureFolder/mysecurefile.pdf", @"test.pdf",
/// @"application/pdf");</code>
/// </example>
/// <example>
/// <code>WriteFileToResponse(@"secureFolder/mysecurefile helpful hints.pdf", @"test.pdf");</code>
/// </example>
/// </summary>
/// <param name="secureFilePath">Relative path to the file to download from our 
/// secure folder</param>
/// <param name="userFilename">Name of file the user will see</param>
/// <param name="contentType">MIME type of the file for Response.ContentType, 
/// "application/octet-stream" is a good catch all. A list of other possible values 
/// can be found at http://msdn.microsoft.com/en-us/library/ms775147.aspx </param>

public void WriteFileToResponse(string secureFilePath, string userFilename, 
    string contentType = @"application/octet-stream")
{
    // Process the file in 4K blocks
    byte[] dataBlock = new byte[0x1000];
    long fileSize;
    int bytesRead;
    long totalBytesRead = 0;

    using (var fs = new FileStream(Server.MapPath(secureFilePath), 
        FileMode.Open, FileAccess.Read, FileShare.Read))
    {
        fileSize = fs.Length;

        Response.Clear();
        Response.ContentType = contentType;
        Response.AddHeader("Content-Disposition", 
            "attachment; filename=" + userFilename);

        while (totalBytesRead < fileSize)
        {
            if (!Response.IsClientConnected)
                break;

            bytesRead = fs.Read(dataBlock, 0, dataBlock.Length);
            Response.OutputStream.Write(dataBlock, 0, bytesRead);
            Response.Flush();
            totalBytesRead += bytesRead;
        }

        Response.Close();
    }
}
This entry was posted in Security and tagged . Bookmark the permalink.

Leave a Reply

Your email address will not be published. Required fields are marked *