Tag Archives: asp.net

Using a HttpModule to protect your content from 3rd party referrals.

 There are certain cases under which you may wish to “discourage” external sites from linking directly to public content (images, documents …) on your site. You may for example, prefer to have user’s visit your site first before accessing any of your resources.

The sample code attached to this post illustrates how to use a HttpModule to act as a filter which prevents third-party sites from linking to your content. You can use this approach to prevent others from linking to pages, images and other resources.

Revision History
v1.0  – Initial code base (25/5/2010) – Download from here.

Section 1.0 – Configuration

a. Unzip the file and deploy it to a folder of your choice.

b. Register “non-standard” extensions – You will need (under IIS 5.x and 6) to register non-standard file extensions (e.g. .js, .jpg, .gif etc.). This enables requests for these resources to be channelled via the ASP.NET engine.

The image below depicts .jpg files being associated with the ASP.NET ISAPI engine. You should limit the HTTP verbs to a range that is supported by your web-site.

Add_file_extension

The image below shows the application configuration screen that is used to add file mappings under IIS.

Application_configuration

c. Open the web.config file and locate the  xanWebFilter node. Next, add file extensions that you wish to ban. I’ve added asmx files which would cause requests from third party sites to be redirected to yahoo.com. Similarly, I’ve added a jpg key that causes all non-validated requests to be transferred to banned.htm

   1:      <!-- Xanthium web-filter specific values. -->
   2:      <xanWebFilter>
   3:          <add key="asmx" value="http://yahoo.com"></add>
   4:          <add key="jpg" value="http://localhost/banned.htm"></add>
   5:      </xanWebFilter>

d. Ensure that the web.config file refers to the HTTP Module (IIS <= v6 or IIS7 classic mode)

<system.web>
    <httpModules>
        <add type="XanIISUtils.BannedExtensionFilter"
          name="xanthiumContentFilter"/>
    </httpModules>
</system.web>


web.config changes (IIS7 integrated mode)

<system.web>
    <httpModules>
        <add type="XanIISUtils.BannedExtensionFilter"
          name="xanthiumContentFilter"/>
    </httpModules>
</system.web>

e. Compile the code and run it. You will see that requests for asmx and jpg files that do not have HTTP referrers set will result in redirects to yahoo and banned.htm respectively.

Section 2.0 – How it works

The application makes use of the functionality provided by the HttpModule class which allows HTTP events to be subscribed to. This allows a piece of code for example, to be invoked when a request is received for a resource managed by the ASP.NET subsystem.

In a similar fashion, you could subscribe to the  Http_EndRequest event to append data (for example) to a stream returned by the server.

The following code in BannedExtensionFilter illustrates how an event is registered

public override void Init(HttpApplication app)
{
     ...
 
    // Register handlers that are called each time a request is received.
    app.BeginRequest += new EventHandler(this.Application_BeginRequest);
}

Next, when an event is called, the framework automatically invokes Application_BeginRequest() within BannedExtensionFilter. This method is responsible for determining whether a request should proceed unhindered or should be redirected. The following steps briefly describe the steps performed –

1. Determine whether the requested resource is part of a banned extension. In our example, this would be true for asmx and jpg files.

2. If the file is “black-listed”, determine whether the request should be redirected based on the return value of IsValidRequest().

IsValidRequest() performs a simple check to determine whether the HTTP referrer is set to the current application server. If the referrer is something else – the method flags this request for rejection.

protected Boolean IsValidRequest(HttpApplication app)
 {
    Uri fromUrl = app.Request.UrlReferrer;
    if ( null == fromUrl )
    {
         return false;
     }
 
     // Referrer is not empty - check to see whether it happens to
     // be this server's name
     return _serverName.ToLowerInvariant() == fromUrl.Host ? true : false;
}

Section 2.1 – Expandability

The current method of validating the HTTP request header for the referrer leaves a lot to be desired, you can start by using some sort of cookie/session check to make things more robust as well as to cater to those (usually custom coded) HTTP clients that may not set a referrer. You can either completely replace IsValidRequest() or override it in a derived class.

Section 3.0 – Conclusion

The code helps illustrate how HTTP modules could be better alternatives to performing similar tasks within the (beloved?) global.asax file. You should typically use this approach if –

1. You are using IIS7 in integrated pipeline mode and want to marshal ALL application requests through your code. I realise that I have not yet talked about setting up the handler for IIS7 – I’ll update the article at a later stage.

2. You need to keep the code modular and reusable within multiple applications. All you need to do is to compile the files into a library and store it within the GAC.

3. You believe in keeping a clean, non-complicated global.asax file.

Section 4.0 – Disclaimer

This code is released “as-is” without any sort of warranty. Please feel free to use it and modify it in your own projects. The code has been kept as simple as possible so that key concepts can be easily understood by the reader.

Please do feel to drop me an email if you find the code useful or if you have any questions.

Anand Balaji