Many web sites suffer from others directly linking to their image, video and other content. This practice is called often called leeching, hot-linking, or inline-linking and causes wasted bandwidth and increased server load to the victim web site.

Last weekend, I wrote a little ASP.NET module that prevents hot linking. It can be used on IIS5 (Windows 2000/XP), IIS6 (Windows Server 2003), and IIS7 (Windows Vista / Longhorn Server).

>> Download it now <<

How does it work?

When a browser follows a hyperlink, or downloads embedded content, from an existing web page, it includes a REFERER header in the request to specify the original url from which this request was made.

This is a useful feature for tracking referrals from other sites, or the path someone takes through your own website. However, it can also be used to identify leeches – websites that point to your own content that you don’t want referred to outside of your own web site.

When a request comes to your web site, the module checks the REFERER header, and if it indicates that the request is from another web site, it rejects the request.

You can specify what content on your website should be protected, and what websites / urls are allowed to refer to it. So, in the end, your website and your friend sites see your images:

Visitors of your website see the image

And leeching websites see (dont worry, you configure your own leech resource to substitue or error status code to return :) ):

Visitors of leeching websites see the redirected image

How do I set it up?

Setting it up is simple:

  1. Download the LeechGuard module and unzip it.
  2. Drop the LeechGuard.dll into your ASP.NET application’s /BIN directory
  3. Copy the web.config file, or add its contents to an existing web.config in your ASP.NET application’s root.

At this point, LeechGuard will provide hot-linking protection for the ASP.NET content in your application. Edit the configuration in web.config to configure things like:

  • What extensions the LeechGuard protects. You probably only want to protect your images / video, but allow aspx and html pages to be linked to from other sites.
  • What "friend" websites / urls can refer to your content.
  • What to do for leeching requests – return an error status code, or redirect to some funny “you are leeching!” image.

Since ASP.NET typically does not process requests for static content, like images, you will also need to map the content you want to protect to ASP.NET before LeechGuard will be able to protect it (this will be different between IIS5 / IIS6 / IIS7):

Mapping IIS content types to ASP.NET

IIS has built in support for serving static files like JPG images, and launching CGI programs. It also provides extensibility for plugging in additional components, called ISAPI extensions, to handle additional resource types. ASP is an ISAPI extension that processes ASP scripts, and ASP.NET is another ISAPI extension that provides processing for ASPX pages and a few other content types.

However, ASP.NET also provides generic services, such as the popular Forms Authentication, authorization, output caching, or custom ones like LeechGuard that are not specific to ASPX pages. Unfortunately, it can only provide these services to content types that are registered to it in IIS scriptmap configuration. Since JPG images are served by IIS, they are not registered to ASP.NET and therefore unable to benefit from ASP.NET services.

With more and more people wanting to use the ASP.NET framework to develop general web infrastructure for IIS, we have tried to solve this problem over the past few releases of both products … culminating in the ASP.NET Integrated pipeline in IIS7.

So, if you want to use ASP.NET to provide services for non-ASP.NET content types, here are your options:

  1. IIS5 + ASP.NET 1.1 and 2.0: Map the desired content type to ASP.NET. ASP.NET can manage serving static files on its own, but does not support CGI, ASP or other ISAPI extensions, so if you use those, you are out of luck.
  2. IIS6 + ASP.NET 2.0: Create a “wildcard mapping” for ASP.NET, passing all requests to ASP.NET. ASP.NET in turn will handle all extensions it knows about, and pass the rest back to IIS to be handled by IIS / other ISAPI extensions. This is great, because it lets you provide ASP.NET processing while continuing to use IIS and other IIS ISAPI extensions to handle their own content.
  3. IIS7 + ASP.NET 2.0 Integrated pipeline. The ultimate answer – ASP.NET extensibility model can now to be used to develop IIS components, regardless of who provides the handling of the request.

So, with that in mind, here is how you enable LeechGuard to protect images and other non-ASP.NET content with these different options:

Enabling LeechGuard to protect images on IIS5

If you are running IIS5 on Windows XP or Windows 2000, you will need to map all extensions that you want to protect to ASP.NET in the IIS Administration console: This will cause all requests to these extensions to be handled by ASP.NET. Because of this, you can only use this with content that ASP.NET knows how to serve, including all static files like images and video – but not ASP pages for example.

Here is how to set that up:

  1. Select your site or virtual directory, and click properties.
  2. Switch to the “Home Directory” tab
  3. Click “Configuration…”
  4. In the “Application Configuration” dialog, click “Add …”
  5. Specify the path to the ASP.NET 2.0 ISAPI (you can get it from any of the other ASP.NET mappings), and the extension you want to map to ASP.NET.

Add extension mapping to IIS5 on Windows XP/2000

Enabling LeechGuard to protect images on IIS6

If you are running IIS6 on Windows Server 2003, you can take advantage of the wildcard mapping support in IIS6 and ASP.NET 2.0, to enable all requests to IIS content to be passed through ASP.NET, but still be handled by the dedicated components in IIS.

This provides better performance, and enables LeechGuard to protect all IIS content, not just what is recognized by ASP.NET.

Here is how to set that up using the IIS Administration console:

  1. Select your site or virtual directory, and click properties.
  2. Switch to the “Home Directory” tab
  3. Click “Configuration…”
  4. In the “Application Configuration” dialog, click “Insert”
  5. Specify the path to the ASP.NET 2.0 ISAPI (you can get it from any of the other ASP.NET mappings), and click OK.

 Adding wildcard scriptmap to ASP.NET 2.0 on IIS6

By creating a wildcard mapping to ASP.NET 2.0, you are essentially funneling all IIS requests to the virtual directory through the ASP.NET request pipeline. However, its not the same as IIS5 or ASP.NET 1.1 - if ASP.NET does not specifically provide a handler for the current request, it the request is forwarded back to IIS for processing.

Enabling LeechGuard to protect images on IIS7

This module thrives on IIS7, taking advantage of the ASP.NET’s Integrated mode to be able to monitor all requests to your server regardless of what content you are protecting. To install it on IIS7 in an application using Integrated mode, you simply need to deploy the module to the application.

No extra steps are required – just copy to your app and use!

LeechGuard Performance Impact

I did a little performance testing on LeechGuard running on IIS6 with wildcard-mapped ASP.NET 2.0:

Performance testing with LeechGuard 

I started out with IIS serving an image with 20 concurrent connections. Then, I configured LeechGuard in two steps, which are marked on the performance graph:

  1. Configure ASP.NET 2.0 wildcard mapping, forcing IIS requests to be passed through ASP.NET. This caused an expected, around 30% drop in RPS, due to ASP.NET now processing every request for the image. Of course, given the power this is giving your static files, its worth it - you can now protect your content with the same authentication and authorization scheme you use for you aspx pages, and use LeechGuard :)
  2. Add the LeechGuard module to the application. This caused a roughly 7% drop in RPS – not bad. I did very little performance optimization of the module, so I have a feeling it could be a little faster with a bit of extra caching (vNext? :) ).

Other things to consider

Here are some other interesting things to think about (and for me to blog sometime in the future):

IIS6+ will automatically use kernel caching for static files, enabling frequently images and such to be stored in the kernel cache. This can seriously improve performance, since it avoid all user mode processing for subsequent requests, saving the expense of IIS and ASP.NET processing.

When using wildcard mapping, kernel caching is disabled. This is very good, because you want to execute LeechGuard or any other ASP.NET functionality you are using on every request.

However, in other cases you may want to kernel cache responses even though you are using ASP.NET, because you do not require per-request processing after you finished building the response the first time, and are ok with it being cached. More in how to do this in the future …

Also, now that you are mapping static files to ASP.NET, using wildcard mapping, or running IIS7 Integrated pipeline, you can finally configure the same forms authentication and authorization rules to user-protect your static content just like you would your ASPX pages.

To do this, just configure your favorite ASP.NET authentication and authorization rules, and watch your images be protected. For an IIS7 example, see Taking Advantage of the Integrated pipeline.

Download it

>> Download LeechGuard here <<

If you have any trouble, questions, etc, let me know. Enjoy!