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.
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.
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: -
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 is called when the module attaches itself to the
HttpApplication object and
Dispose is called when the module is detached from
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: -
Sub Init(ByVal Application As HttpApplication)
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
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: -
AddHandler Application.BeginRequest, AddressOf Me.Application_BeginRequest
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
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.
Public Class RefererFilter
Private Application As HttpApplication
Public Sub Init(ByVal Application As HttpApplication)_
AddHandler Application.BeginRequest, _
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")
If Not refName Is Nothing Then
If Not IsValidReferer(hostName, refName) Then
Private Function IsValidReferer(ByRef host As String, _
ByRef referer As String) As Boolean
Return IIf(referer.StartsWith("http://" & host),_
True, False) End Function
Private Sub TeminateRequest()
Public Sub Dispose() Implements IHttpModule.Dispose
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: -
<add name="RefererFilter" type="YourNamespace.RefererFilter,YourAssemblyName"/>
Make sure you replace the type attribute value to an appropriate value. It should reflect this format:
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!
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!