Secure unauthorized download of ZIP files from your site by using
HttpHandler
|
|
|
|
|
.Net Framework Version: 1.0, 1.1
I was working on an ecommerce web application for a site that sells software
components. The final step in the process was to send an email to customer
where a download link was provided to the ZIP file. I asked the question, what
if I enter the URL to the zip file in my browser. Do you think the web
application's implementation will be able to detect that I am trying to get
your ZIP file without being authenticated to the site. The immediate response
from one developer was, I have forms authentication enabled for the
application. so you will have to authenticate first. Hmm.. do you think it is
going to work, lets try it? To this developer's surprise, I was able to
download the file without being authenticated. This whole conversation lead to
defining the requirements of the download process.
-
We need a process to deny unauthenticated users access to download files.
-
We need a process to deny unauthorized users access to download file.
-
We need a process to hide the actual location of the download file from the
user.
If you think it in terms of security principles, these 3 requirements directly
translate to Authentication, Authorization and Obfuscation. So if we can
fulfill these requirements of security, our job is done. So lets see what this
means in terms of implementing this is ASP.Net application.
Authentication
Although you have set FORMS authentication for web application it does not stop
anonymous user from accessing ZIP file directly. the reason is that your
application is not configured for ASP.Net ISAPI extension to handle files of
this type. You need a new file mapping in your application in IIS so that
access to ZIP file is handled bt ASPNET_ISAPI.DLL. Once you have done that,
every time somebody tries to access the ZIP file, the request will have to go
through ASP.Net framework. And if you are not authenticated user, you will be
redirected to Login page designated by your web application. Look at the Use
ASP.Net to protect file types article to get more information on how to add
file mappings.
Authorization
We solved our first requirement. Now we have the second problem. Consider this
scenario. Customer A bought ProductX and he has registered with your web site.
So now you send him the link to download ProductX file. Now he changes your
download link URL and try to get to ProductY ZIP file. He is already an
authenticated user so our first step is not going to prevent him from getting
any other ZIP file that he is not authorized to do so. What about if I send a
download link like
http://www.mycompany.com/ProductX.zip?vc=DGH78W&pr=89TY03 to the customer?
Now you are thinking, he is sending a URL that has some information sent in
query string. Bingo... thats what we are going to do. We will send some
information in query string which could be some authentication codes issued for
that download to that particular customer. We process it to make sure that its
the authorized user who is downloading the file. Now you are saying its all
find and dandy but this URL points to a ZIP file. How am I going to process it?
This is where our wonderful HttpHanlder is going to help us. You can read more
about HttpHandler in .Net framework documentation. What I did was, implemented
a HttpHandler for ZIP files and added the entry in Web.config file of the
application. What this means is that every time a request comes for a ZIP file,
ProcessRequest method of my handler is called. In this method I process the
query string to figure out if user is authenticated and authorized or not. If
he is not, I set StautsCode property value of Response to 404 so that user gets
the message that file does not exist. And if he or she is the right user,
response is redirected to the ZIP file.
<SYSTEM.WEB>
<HTTPHANDLERS>
<ADD type="ThirdEye.Web.HttpHandler.DldFileHttpHandler,
ThirdEye.ZipFileHttpHandler" path="*.zip" verb="*" />
</HTTPHANDLERS>
<SYSTEM.WEB>
Obfuscation
So we have made sure that only authenticated and authorized user can access the
ZIP file. But now you must be thinking that by redirecting the response to the
ZIP file we have told the user the actual location of the ZIP file. And the
requirement is that the user should not know about it. What I did was that in
ProcessRequest method, after I verified the user, I read the ZIP file in
FileStream and wrote the binary data directly into OutputStream of Response.
Now user gets is a nice dialog box asking if he or she wants to open or save
the file.
try
{
FileStream oFile = new FileStream(strPhPath, FileMode.Open);
ctx.Response.Charset = "";
ctx.Response.ContentType = "application/zip";
BinaryReader br = new BinaryReader(oFile);
for (long l = 0; l < oFile.Length; l++)
{
ctx.Response.OutputStream.WriteByte(br.ReadByte());
}
}
catch (Exception ex)
{
Trace.WriteLine(ex.Message);
ctx.Response.StatusCode = 404;
}
Final Thought
You must be thinking why go through the process of adding a new HttpHandler and
file mapping, why not simply send a link to an ASPX page and then do the query
string processing. You can do that too. But that does not prevent anonymous
users to keep trying to access the ZIP files by trying different permutations
and combinations of URLs. This way it is guaranteed that user is going to get
access denied message is he has not authenticated himself.
|