![]() |
Web Development »
Web Security »
Security
Intermediate
Secure File Download Using Basic AuthenticationBy Mohd Faraz (Lucky)Secure file download using Basic Authentication. The interesting part is that we maintain two separate entry points for uploading and downloading a file. |
C#, HTML, .NET, Win2K, WinXP, Win2003, ASP.NET, IIS, Visual Studio, IE 6.0, Dev
|
|
Advanced Search |
|
|
|
||||||||||||||||

Security has always been a top issue for all kinds of applications, especially Web applications. Web apps are accessible to almost the entire universe, and are open to attack. Most of the web applications provide the file download feature, the real time challenge is not in providing such a feature, but in securing such operations. Recently, I dealt with an application which demands for secure file upload and download, during which I did wide research, so I thought of sharing it with the world to make it worth.
You may find several articles on the internet talking about secure downloads, but this article is a bit different from all those, because it distinguishes between upload and download by providing two different entry points for them.
The following article depicts how secured file download can be achieved using IIS basic authentication.
Before we start, let's refresh our memory and learn some basics.
An ASP.NET application has two separate authentication layers. That is because ASP.NET is not a standalone product. Rather, it is a layer on top of IIS. All requests flow through IIS before they are handed to ASP.NET. As a result, IIS can decide to deny access without the ASP.NET process even knowing that someone requested a particular page. Here is an overview of the steps in the joint IIS and ASP.NET authentication process:
In general, any web application contains a single virtual directory and a single Uploads folder, to/from which end users upload/download files. Here, I'm playing a little trick: though upload and download happens to/from the same folder, I'm keeping two different entry points for them. I.e., I create two different virtual directories which point to the same physical folder.
Keeping the uploads folder as it is, we are creating two entry points for the files, one is through http://localhost/security/uploads, and the other through http://localhost/downloads. Though both the virtual directories are pointing to the same folder, based on their settings, they will behave differently.


Modify the following parameters in the web.config files as per your application needs:
//Application uploads folder virtual path
<add key="UploadPath" value="/Security/Uploads" />
//Entry point for downloads folder, a virtual path
<add key="DownloadURL" value="http://localhost/downloads" />
//Windows user name
<add key="BasicAuthenticationUser" value="administrator" />
//Windows user password
<add key="BasicAuthenticationPWD" value="admin$123" />
Now, let's start learning...................
What is Basic Authentication - when an unauthenticated request comes into the web server, the web server returns an HTTP 401 response, prompting the client for its credentials. The client re-requests the same resource, passing the username and password in a base-64 encoded HTTP header. (The base-64 encoding does not encrypt or protect the credentials; it merely ensures that the characters sent over the wire are in a format that won't conflict with any reserved characters.) Since the credentials are sent over the wire in plain-text, Basic Authentication should only be used when using SSL, since this ensures that the entire contents of the HTTP request are encrypted. However, in our case, we are passing the credentials to the same server through localhost, so passing credentials as clear text would not be a problem.
The .NET Framework provides the WebClient class, which is designed to simplify the HTTP request process. It contains common methods for sending data to and receiving data from a resource identified by a URI. The HttpWebRequest class is used to generate the request, and HttpWebResponse is used to retrieve the response from the server. Typically, HttpWebRequest and HttpWebResponse serve all the purposes, but in the case of Basic Authentication, an extra class comes into picture, i.e., CredentialCache.
Both the WebClient and HttpWebRequest classes make it easy to include authentication information in the request through their Credentials properties. The Credentials property accepts an object that implements ICredentials. The CredentialCache class provides a store for credentials. The intent of the CredentialCache class is to store a set of credentials for the user. When a request is made to a resource, the CredentialCache class can be interrogated and the appropriate credentials can be extracted based on the resource being requested.
The simplest use of this class involves just a few lines of code. The steps we need to perform include:
DownloadData method, passing in the URL (which returns an array of Bytes).
Byte using Response.BinaryWrite, which in turn prompts the user to download the file. The following code shows how to use the CredentialCache class and the WebClient's Credentials property to make a request to a URL that is protected via Basic Authentication:
using System;
using System.Collections;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Web;
using System.Web.SessionState;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.HtmlControls;
using System.Net;
using System.IO;
namespace security
{
/// <SUMMARY>
/// Summary description for SecureFile.
/// </SUMMARY>
public class SecureFile
{
public SecureFile()
{
//
// TODO: Add constructor logic here
//
}
public bool UploadFile(HtmlInputFile inputfile)
{
try
{
string fileName = "";
string DirPath = "";
if(( inputfile.PostedFile != null ) &&
( inputfile.PostedFile.ContentLength > 0 ))
{
DirPath=HttpContext.Current.Server.MapPath(
System.Configuration.ConfigurationSettings.AppSettings[
"UploadPath"]);
fileName = System.IO.Path.GetFileName(
inputfile.PostedFile.FileName );
inputfile.PostedFile.SaveAs( DirPath + "\\" + fileName );
}
return true;
}
catch
{
return false;
}
}
public bool DownloadFile(string strFile)
{
try
{
string strDownloadURL=
System.Configuration.ConfigurationSettings.AppSettings[
"DownloadURL"];
string strUser=
System.Configuration.ConfigurationSettings.AppSettings[
"BasicAuthenticationUser"];
string strPWD=
System.Configuration.ConfigurationSettings.AppSettings[
"BasicAuthenticationPWD"];
string strURL=strDownloadURL + "\\" + strFile;
//Creating an instance of a WebClient
WebClient req=new WebClient();
//Creating an instance of a credential cache,
//and passing the username and password to it
CredentialCache mycache=new CredentialCache();
mycache.Add(new Uri(strURL),"Basic",
new NetworkCredential(strUser,strPWD));
req.Credentials=mycache;
//Creating an instance of a Response object
HttpResponse response = HttpContext.Current.Response;
response.Clear();
response.ClearContent();
response.ClearHeaders();
response.Buffer= true;
//Keep the current page as it is, and writes
//the content to an new instance,
//which prompts the user to download the file
response.AddHeader("Content-Disposition",
"attachment;filename=\"" + strFile + "\"");
byte[] data=req.DownloadData(strURL);
response.BinaryWrite(data);
response.End();
return true;
}
catch(Exception ex)
{
if(ex.Message=="The remote server " +
"returned an error: (404) Not Found.")
throw new Exception("File not found");
else if(ex.Message=="The remote server" +
" returned an error: (401) Unauthorized.")
throw new Exception("Unauthorized access");
return false;
}
}
}
}
Enjoy!!! Any feedback would be appreciated.
For quick implementation and demonstration purposes, I have used the administrator user, but I strongly recommend you to create a new user which has only Write permissions to the Uploads folder and no other permissions on the server/system.
| You must Sign In to use this message board. | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
General
News
Question
Answer
Joke
Rant
Admin
|
PermaLink |
Privacy |
Terms of Use
Last Updated: 19 Mar 2006 Editor: Smitha Vijayan |
Copyright 2006 by Mohd Faraz (Lucky) Everything else Copyright © CodeProject, 1999-2009 Web13 | Advertise on the Code Project |