Click here to Skip to main content
15,867,453 members
Articles / Web Development / ASP.NET
Article

Using HTTP Modules To Combat Leeching

Rate me:
Please Sign up or sign in to vote.
3.38/5 (14 votes)
3 Dec 20037 min read 99.6K   49   9
An article to demonstrate how HTTP Module-based filtering can prevent leeching.

Introduction

What the article explains

The article explains how an HTTP module can be used to combat leech requests to resources on your domain through GET or POST HTTP request methods. The code snippet provided defines a class that implements the IHttpModule interface. An instance of this class will hook into the ASP.NET runtime and intercept the BeginRequest event of the HttpApplication object and determine if the requested URI came from a leech link on another website. Leech links are simply links pointing to resources on your site without your knowledge or authorization.

This technique can be used to prevent the outside world from posting links to resources on your domain without authorization to do the same. For example, if you maintain a list of sites that have been authorized to provide links to your website, then you can put into effect a selective screening routine. On the other hand, if there are domains that you do not want to be referred from, this technique will again, prove equally useful. I have not provided the code to these ends though. My intent here is to simply illustrate a basic possibility. But you could mail me if you are interested to know how to go about it, but I believe you should be able to pull it off without much ado after reading through this article.

Background

ASP.NET Pipeline

The ASP.NET pipeline represents a series of extensible objects that work in a sequential-chain and act on an incoming request, one after the other. As the requests pass through the pipeline, they are modified and filtered until they are finally handed over to a handler object that emits a suitable response back to the client. Through the use of these modules and handlers, we can effectively extend the capabilities our web server, just like what ISAPI extensions and filters are used to do for IIS.

HttpModules

An HTTP module is an assembly that handles events raised by an HttpApplication object. ASP.NET includes a set of HTTP modules that can be used by your application. For example, the SessionStateModule is provided by ASP.NET to supply session-state services to an application. There are a number of other system-level HTTP modules, providing services ranging from authentication to state management to output caching. Here is the list of modules registered on my machine's machine.config file: -

XML
<httpModules>
<add name="OutputCache"
type="System.Web.Caching.OutputCacheModule"/>
<add name="Session"
type="System.Web.SessionState.SessionStateModule"/>
<add name="WindowsAuthentication"
type="System.Web.Security.WindowsAuthenticationModule"/>
<add name="FormsAuthentication"
type="System.Web.Security.FormsAuthenticationModule"/>
<add name="PassportAuthentication"
type="System.Web.Security.PassportAuthenticationModule"/>
<add name="UrlAuthorization"
type="System.Web.Security.UrlAuthorizationModule"/>
<add name="FileAuthorization"
type="System.Web.Security.FileAuthorizationModule"/>
</httpModules>

The number of modules that get to intercept the request is based upon these settings within the host machine's machine.config file and the application's web.config file. Note that, HTTP modules are typically executed for every request irrespective of the file type.

When an HTTP module is hooked into the pipeline (via an entry in web.config), the ASP.NET runtime calls the module's Init and Dispose methods. Init is called when the module attaches itself to the HttpApplication object and Dispose is called when the module is detached from HttpApplication. The Init and Dispose methods represent the module's opportunity to hook into a variety of events exposed by the HttpApplication object. These events include the beginning of a request, the end of a request, a request for authentication, and so forth. The Init method takes the HttpApplication object and maps event handlers to the desired events.

To make a class act as a module, it should implement the member signatures of the IHttpModule interface. The members are as follows: -

  1. Sub Init(ByVal Application As HttpApplication)
  2. Sub Dispose()

HttpApplication

The HttpApplication object raises several events that reflect different processing stages for a request. Any HttpModule class registered with the HttpApplication object to receive notification can consume these events. As and when the HttpApplication object raises an event, the same event is passed to all the modules registered to receive notification of the event. The ordinal of a module in the chain is determined by its order in the module listing within the web applications configuration file (machine.config and web.config).

The events that are raised by the HttpApplication object are as follows (as listed in MSDN): -

  • AcquireRequestState - When ASP.NET acquires the current state (for example, session state) associated with the current request.
  • AuthenticateRequest - When a security module has established the identity of the user.
  • AuthorizeRequest - When a security module has verified user authorization.
  • BeginRequest - When the first event in the HTTP pipeline chain of execution responds to a request.
  • Disposed - When ASP.NET completes the chain of execution when responding to a request.
  • EndRequest - When the last event in the HTTP pipeline chain of execution responds to a request.
  • Error - When an unhandled exception is thrown.
  • PostRequestHandlerExecute - When the ASP.NET handler (page, XML Web Service) finishes execution.
  • PreRequestHandlerExecute - Just before ASP.NET begins executing a handler such as a page or XML Web Service.
  • PreSendRequestContent - Just before ASP.NET sends content to the client.
  • PreSendRequestHeaders - Just before ASP.NET sends HTTP headers to the client.
  • ReleaseRequestState - After ASP.NET finishes executing all request handlers; also causes state modules to save the current state data.
  • ResolveRequestCache - When ASP.NET completes an authorization event to let the caching modules serve requests from the cache, bypassing execution of the handler (the page or XML Web Service, for example).
  • UpdateRequestCache - When ASP.NET finishes executing a handler in order to let caching modules store responses that will be used to serve subsequent requests from the cache.

Using the code

RefererFilter.vb

This is our HTTP module class. It implements the IHttpModule interface. The Init method is where you inform the global HttpApplication object about our interest in being notified about its events. In this case, we express a desire to handle its BeginRequest event with the following statement: -

VB
AddHandler Application.BeginRequest, AddressOf Me.Application_BeginRequest

The AddHandler method passes a pointer to our filter method (Application_BeginRequest) as a delegate to the Application object. The pointer to the filter method is obtained by using the AddressOf operator.

When the BeginRequest event is raised by the HttpApplication object, the latter will invoke the Application_BeginRequest method of our class. All this method does is to check if the referral URI is part of the host domain. This comparison is done by the IsValidReferal function, which returns True if the domains are the same.

Carrying on, if the IsValidReferer function returns False, we call the TerminateRequest function. All that it does is to prematurely terminate the current Request. I guess I have provided just enough comments in the code for you to follow without having to bear through my explanation.

VB
Public Class RefererFilter
    Implements IHttpModule
    Private Application As HttpApplication

    Public Sub Init(ByVal Application As HttpApplication)_
                                   Implements IHttpModule.Init
        'Register our Filter method with the HttpApplication 
        'object to receive notification of its BeginRequest event.
        AddHandler Application.BeginRequest, _
            AddressOf Me.Application_BeginRequest
    End Sub

    'This method is called by the HttpApplication object when 
    'the HttpContext object has been prepared for the URI request
    Public Sub Application_BeginRequest(ByVal sender _
               As Object, ByVal events As System.EventArgs)
        Application = CType(sender, HttpApplication)
        Dim Request As HttpRequest = Application.Context.Request
        Dim hostName As String = Request.ServerVariables("HTTP_HOST")
        Dim refName As String = Request.ServerVariables("HTTP_REFERER")
        'Check if HTTP_REFERER holds a value
        If Not refName Is Nothing Then
            'Check if the value in refName is a authorized or valid
            If Not IsValidReferer(hostName, refName) Then
                TeminateRequest()
            End If
        End If
    End Sub

    ' This function contains the Authorization or 
    ' Validation logic to apply on the Referer URL
    ' Currently, the code below will only check to se if
    ' the host name is a part of the referer URL
    Private Function IsValidReferer(ByRef host As String, _
                          ByRef referer As String) As Boolean
        'referer will contain the previous url, while host 
        'contains only the current domain name.
        Return IIf(referer.StartsWith("http://" & host),_
           True, False) 'return TRUE if the domain is the same.
    End Function
    Private Sub TeminateRequest()
        'YOU CAN SET AN ERROR RESPONSE IF YOU WISH
        'OR REDIRECT THE REQUEST TO ANOTHER URI.. 
        'your homepage could be a starting point.
        'OR SIMPLY TERMINATE THE REQUEST...THIS IS NOT RECOMMENDED 
        'EXCEPT IF YOUR INTENT IS TO ILLUSTRATE.
        'I choose to illustrate here the termination of a request 
        'before it flows to any more modules and ultimately to the handlers.
        Application.CompleteRequest()
        'The response in this case will be blank.
    End Sub
    Public Sub Dispose() Implements IHttpModule.Dispose
        'Under ordinary circumstances, we don't really 
        'need to do anything here.
    End Sub
End Class

Compile this class into an assembly and note the namespace, class and assembly name for registering the filter in the web.config file of your website as follows: -

XML
<httpModules> 
<add name="RefererFilter" type="YourNamespace.RefererFilter,YourAssemblyName"/> 
</httpModules>

Make sure you replace the type attribute value to an appropriate value. It should reflect this format:

XML
type="YourNamespace.ClassName,AssemblyName"

Code In Action

Case 1) Browse to your website by typing the URL in your browser's address field. Your website should conveniently respond with the contents of the resource that was requested. This happens because HTTP-REFERER is empty, and the IsValidReferer function, predictably does not run, and it should not. So if you were at 'x.com' and decided to visit 'your-domain.com' by typing it in to the address bar, 'your-domain' would not know you were previously at x.com. Furthermore, redirecting to a URL in your domain from another domain can be effectively compared to typing in a URL into your browser's address field and pressing GO. So I must warn you that this ploy is not full-proof as such! Innovate!

Case 2) Now we need to have a link on a page part of another domain that points to a URL on your website's domain. Pressing this hyperlink should result in our Filter terminating our request since HTTP_REFERER contains a value and the IsValidReferer returns a value of False. You can modify the code to cause a redirect or do whatever else you can think of to prevent the leeching. So, let's say you went to the website of X (www.x.com) and there's a link to your web page at 'your-domain.com'. You clicked the link and went to 'your-domain.com'. In this case, HTTP_REFERER tells 'your-domain' that you had come from x.com and the referer filter at 'your-domain.com' will terminate the request. As I had mentioned before, terminating the request completely is not always the best POA (Plan Of Action). A little imagination should make sparks fly!

Conclusion

I suppose combating leech links is a concern for a whole lot of websites. Face it! Nobody enjoys being ripped off. If there is a way to prevent it, do so by all means.

"Prevention is better than cure"

Season's greetings to all!

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Web Developer
India India
Jaison John is currently working as a Software Engineer at Net Asset Management,India. He is an Electrical & Electronics engineering graduate from India with over 4 years of development experience behind him.His main areas of interest have been Visual Basic (both version 6 and .NET flavors),ActiveX, DHTML and most recently ASP.net and Winforms Development in C#/VB.net.

Comments and Discussions

 
GeneralEasy To Be Countered Pin
Izzet Kerem Kusmezer27-Jan-09 4:23
Izzet Kerem Kusmezer27-Jan-09 4:23 
Generalprevent image leeching Pin
OzMoyal2-May-07 1:12
OzMoyal2-May-07 1:12 
QuestionHow does this affect RSS syndication ? Pin
CreativeNRG10-Aug-05 3:55
CreativeNRG10-Aug-05 3:55 
Generalweb services Pin
Member 136996118-Sep-04 13:26
Member 136996118-Sep-04 13:26 
GeneralRe: web services Pin
KingLeon6-Nov-04 17:47
KingLeon6-Nov-04 17:47 
QuestionDoes this work for resource files also? Pin
Gery Dorazio13-Aug-04 21:08
Gery Dorazio13-Aug-04 21:08 
AnswerRe: Does this work for resource files also? Pin
KingLeon14-Aug-04 21:02
KingLeon14-Aug-04 21:02 
Generalhttp handlers Pin
chandler sue26-May-04 7:34
chandler sue26-May-04 7:34 
GeneralRe: http handlers Pin
KingLeon26-May-04 9:40
KingLeon26-May-04 9:40 

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

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.