Click here to Skip to main content
Click here to Skip to main content

Forbidden Direct Download HTTP Filter

By , 4 Jul 2006
 

Sample Image

Introduction

This DLL will enable an IIS website to redirect all requests to the home page when there are requests for EXE, RAR, Zip files that have no reference or have a reference from outside of your own web site. For example, if someone tries to download http://www.yoursite.com/download/dd.exe by clicking on that link from another site, they will be redirected to http://www.yoursite.com/.

Background

A few days ago, I discovered that 80% of the traffic to my website is to download an EXE file which I give as a free download on the Internet. After check with the page view traffic, I found that users were downloading the EXE file without even looking at my web page. :( I did some search on the Internet and realised there are no free tools to stop this and to find the difference between direct download from a link in another site and download from my own website. I decided to write an HTTP filter to do this.

Key knowledge: When downloading a file from your website by clicking on a link from another website, the page will have an HTTP_Reference value which has the name of the other website. For example, if someone tries to download http://www.arcai.com/download/netcut.exe by clicking on that link from http://www.othersite.com/downloadlink.html, then the HTTP request to your website will come with a HTTP_REFERER: http://www.othersite.com/downloadlink.html.

If someone tries to download files directly (not from another web page), the HTTP_REFERRE will be empty. And, if someone tries to download http://www.arcai.com/download/netcut.exe by clicking on a link from your own website, then the HTTP_REFERER will have your website's URL.

This can be detected by programming on the HTTP FILTER DLL project.

So, a few hours later, this project was released. It is very simple: a one line fix to the source code of the default ISAPI project of VC++ 2003. Actually, only one virtual function has been overwritten. No configuration is needed to use this tool. I had this tool enabled on one of my sites with in a second after its release. And, it has been running very well. Here is a demo. Click on the link, and you will be taken to http://www.arcai.com/, and from there, click on the download link, and you can then download the file.

Using the code

There are two parts that were modified in the default CHttpFilter project.

  1. I addrf a SF_NOTIFY_URL_MAP to dwflags, so our OnUrlMap will be run.
  2. //
    //
    BOOL CNoDirectExeFilter::GetFilterVersion(PHTTP_FILTER_VERSION pVer)
    {
       CHttpFilter::GetFilterVersion(pVer);
    
       pVer->dwFlags &= ~SF_NOTIFY_ORDER_MASK;
    
       pVer->dwFlags |= SF_NOTIFY_SECURE_PORT | SF_NOTIFY_NONSECURE_PORT | 
                           SF_NOTIFY_END_OF_NET_SESSION | SF_NOTIFY_URL_MAP;
       pVer->dwFlags |= SF_NOTIFY_ORDER_LOW;
    
       TCHAR sz[SF_MAX_FILTER_DESC_LEN+1];
       ISAPIVERIFY(::LoadString(AfxGetResourceHandle(),
             IDS_FILTER, sz, SF_MAX_FILTER_DESC_LEN));
       _tcscpy(pVer->lpszFilterDesc, sz);
       return TRUE;
    }
  3. We overwrite a virtual function OnUrlMap. This function checks all the HTTP requests, and deals with all requests for EXE, zip, and RAR files (you can add more file extensions to the source code by simply fixing it).
  4. DWORD CNoDirectExeFilter::OnUrlMap(CHttpFilterContext* pfc, 
                              PHTTP_FILTER_URL_MAP pUrlMap)
    {
       DWORD dwSize;
       
       CString sPath;
       sPath=pUrlMap->pszURL;
       sPath=sPath.Right(3);
       if(sPath.MakeLower()!="exe"&&sPath.MakeLower()!= 
                 "zip"&&sPath.MakeLower()!="rar")
          return SF_STATUS_REQ_NEXT_NOTIFICATION;
       //if add more file ext here.
    
       
       bool bHaveReferer=false;
       
       char szAddress[255];
       memset(szAddress,0,255);
       dwSize = sizeof(szAddress);
       
       CString Referer;   
       
       //Get HTTP_REFERER Value
    
       if (pfc->GetServerVariable("HTTP_REFERER", szAddress, &dwSize))
       {       
          Referer=szAddress;
          Referer=Referer.MakeLower();
          bHaveReferer=true;
       }
    
       memset(szAddress,0,255);
       dwSize = sizeof(szAddress);
       //GET SERVER VALUE   
    
       CString ServerName;
       if(pfc->GetServerVariable("SERVER_NAME", szAddress, &dwSize))
       {
             ServerName=szAddress;
             ServerName=ServerName.MakeLower();
             if(bHaveReferer)
             {
                if(-1==Referer.Find(ServerName))
                   bHaveReferer=false;
             }
       }
    
       if(!bHaveReferer)
       {
          CHAR szRedirect [256];
          
         sprintf(szRedirect, "Location: http://%s\r\n\r\n", ServerName.GetBuffer(0));
         pfc->ServerSupportFunction ( SF_REQ_SEND_RESPONSE_HEADER, 
                (LPVOID) "302 Redirect", 
                (DWORD *) szRedirect, 
                0 );
         
          // we are done with this request
    
          return SF_STATUS_REQ_FINISHED_KEEP_CONN;
       }
        
       return SF_STATUS_REQ_NEXT_NOTIFICATION;
       return CHttpFilter::OnUrlMap(pfc, pUrlMap);
    }
    //

How to use

  1. Download the ready-to-use DLL file, and unzip the files into any folder accessible by IIS, like C:\winnt\system32\.
  2. Go to the ISAPI filter setting of the website which you want to enable these features.
  3. Click on the Add button and select nodirectexe.dll.
  4. Restart W3SVC.

Now, all your EXE, zip, and RAR files are under the protection of this DLL. All direct downloads and downloads by click on links other than that on your own website will be redirected to your front page URL.

Points of interest

Do it yourself sometime is the only and the best way. Oh, you will need C++ !!. :)

History

This is first time release. My home Page will have a more recent version released.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

cceye
Web Developer
China China
Member
I enjoy those tiny code which changs the fact of the world.
I start do Perl for write a DB engine with HTML template , which kind of like php. which was 1998.
used to work with security software company for design and coding .
now I do freelance in at my home
most of my interest is Forex trade, and IP technology.
VC++ for 5 years. one of my favour tool I wrote is NetCut.

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
QuestionIt doesn't work...memberTheMattster25 May '12 - 2:54 
I tried it in my chrome browser, clicked on the 'demo' link and was immediately asked where I wanted to save the netcut.exe file. No redirection took place.
 
Sorry.
GeneralThis is wrong - referer header is optional per W3C specsmemberrlivelyppk11 Jul '06 - 7:21 
You should never lock people out based solely on the referer header. According to the HTTP protocol, the referer header is optional and may be omitted by user agents. As a matter of fact, W3C actually recommends that browser users have an option to disable the referer, as the Opera browser does:
 
http://www.w3.org/Protocols/rfc2616/rfc2616-sec15.html#sec15.1.3
 
15.1.3 Encoding Sensitive Information in URI's
 
... it is strongly recommended that the user be able to select whether or not the Referer field is sent. For example, a browser client could have a toggle switch for browsing openly/anonymously, which would respectively enable/disable the sending of Referer and From information.
 

http://www.w3.org/Protocols/HTTP/HTRQ_Headers.html#z14
 
Referer:
 
This optional header field allows the client to specify, for the server's benefit, the address ( URI ) of the document (or element within the document) from which the URI in the request was obtained.
 
This allows a server to generate lists of back-links to documents, for interest, logging, etc. It allows bad links to be traced for maintenance.
GeneralRe: This is wrong - referer header is optional per W3C specsmemberrlivelyppk11 Jul '06 - 7:25 
If you do insist on leaving this check in, you should bypass it and allow downloading of the file in the case of a missing or blank referer. If someone attempts to download the file with the referer disabled (proxies sometimes remove the referer, and some browsers allow disabling of them), then they will be redirected to your home page, even if they click the download link from your page! This will be frustrating and confusing since there is no indication of why the download isn't working, and the user will eventually give up and never return to your site.
GeneralRe: This is wrong - referer header is optional per W3C specsmembercceye12 Jul '06 - 5:06 
I admit it could happen.
 
To not redirect File Download Request with NO HTTP_REFERER , change the code as following
 
if (pfc->GetServerVariable("HTTP_REFERER", szAddress, &dwSize))
{
Referer=szAddress;
 
Referer=Referer.MakeLower();

bHaveReferer=true;
 

}
else //add line 1
return SF_STATUS_REQ_NEXT_NOTIFICATION; //add line 2. those two line will return when the request have no referer at all.
 
thanks for comment
GeneralRe: This is wrong - referer header is optional per W3C specsmemberrlivelyppk12 Jul '06 - 5:50 
Thank you for the response. This way you can still achieve your goal for people that do have the referer enabled (external links to your file will be redirected to the information page about it), but you won't be locking out users where the referer is missing for whatever reason. Best of both worlds, I'd say!
Jokechinamemberzhaojicheng5 Jul '06 - 21:57 
chinaren.good
GeneralGreatmember2ASoft5 Jul '06 - 9:25 
I dont think I'll need this right now, but soon enough I'll have a use for it. Its a great idea and implementation. Although there are many tools/downloaders that allow you to bypass this(ie. flashget can set the referrer to the file itself automatically, and allows you to change the referrer). Still a great article though.
 
P.S. Your language is a bit...unusual :p no offence.
 
rara avis in terris
GeneralI hate youmemberEnnis Ray Lynch, Jr.5 Jul '06 - 5:30 
Actually I don't harbor any animosity. However, I am sure there is a firefox extension that will allow fake a referral.
 
To really restrict the download you will most certainly need a session key.
 
Another, and really good method, imho, is to create fake names for the links, ie 12fhfr.exe which are not actually files and then have a server-side app translate it into a download. This allows for easy expiration and other controls over content. Many of the File upload websites use this technology.
 
"Until the day of his death, no man can be sure of his courage" -- Jean Anouilh
GeneralI like the idea.memberANewCoder5 Jul '06 - 3:24 
I am still studying the code to make sure I understand it. However, I wanted to compliment you on one of the most readable Privacy Policies I've seen.

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Permalink | Advertise | Privacy | Mobile
Web01 | 2.6.130523.1 | Last Updated 5 Jul 2006
Article Copyright 2006 by cceye
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid