Introduction

As a website developer, we sometimes don't want the images on our own website to be directly referenced and showed on other's website. It can cause a lot network bandwidth for our datacenters in some cases, which means costing money for us to pay for the one who use our images.

For example, your website is A.com, you have an image on http://a.com/facepalm.jpg and B.com used your image on b.com by putting an <img> tag in their html, it can cause network request going in to your server consuming your resources.

A lot of websites prevent image hotlinking. Let me show you how we can do it in ASP.NET or ASP.NET Core application.

The technique I use is URL Rewrite. As we know, every http request has some headers, one of them is the "HTTP referer". You can check more details on Wikipedia here. It applies to image files also, if the image is hotlinking from another website. It will have HTTP referer values of another website.

In the example above, if the user lands on b.com visiting http://a.com/facepalm.jpg, for a.com's web server, the http requst for this particular image will have an http header named "referer" with value of "http://b.com....". This is where we will check and block the request.

 

ASP.NET (.NET Framework) Applications

For classic ASP.NET (.NET Framework) application on IIS, you have to install the URL Rewrite extension on IIS https://www.iis.net/downloads/microsoft/url-rewrite.

Create a file named "UrlRewrite.config" under your application root directory with the content below:

<rules>
  <rule name="Prevent Image Hotlinking">
    <match url=".*\.(gif|jpg|png)$"/>
    <conditions>
      <add input="{HTTP_REFERER}" pattern="^$" negate="true"/>
      <add input="{HTTP_REFERER}" pattern="^http://a.com/.*$" negate="true"/>
    </conditions>
    <action type="Rewrite" url="/content/images/no_hotlinking.png"/>
  </rule>
</rules>

This rule means, for the image file type that ends with .gif, .jpg, .png, check the HTTP Referer header, if it is not starting with "http://a.com" return the image "/content/images/no_hotlinking.png", which is a prepared warning image like below:

Then, add this section into your web.config, under system.webServer node

<rewrite>
    <rules configSource="UrlRewrite.config" />
</rewrite>

 

ASP.NET Core Applications

For ASP.NET Core applications, you don't need to install anything on your hosting environment. 

Prepare a similar file under your application root UrlRewrite.xml, but with one difference: you have to add "rewrite" as root node.

<rewrite>
  <rules>
    <rule name="Prevent Image Hotlinking">
      <match url=".*\.(gif|jpg|png)$"/>
      <conditions>
        <add input="{HTTP_REFERER}" pattern="^$" negate="true"/>
        <add input="{HTTP_REFERER}" pattern="^http://a.com/.*$" negate="true"/>
      </conditions>
      <action type="Rewrite" url="/images/no_hotlinking.png"/>
    </rule>
  </rules>
</rewrite>

Note: You have to set this file to always copy to output directory, otherwise it won't work!

<ItemGroup>
  <None Update="UrlRewrite.xml">
    <CopyToOutputDirectory>Always</CopyToOutputDirectory>
  </None>
</ItemGroup>

Open your Startup.cs, add this code to Configure method:

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    ...
    using (var urlRewriteStreamReader = File.OpenText("UrlRewrite.xml"))
    {
        var options = new RewriteOptions().AddIISUrlRewrite(urlRewriteStreamReader);
        app.UseRewriter(options);
    }
    ...
}

Then it will work the same way as the above ASP.NET Framework application.

 

Tips and Tricks

In real world cases, websites often have multiple domains with/out https and with/out port number. like:

For production:

  • http://a.com
  • https://a.com

For development:

  • http://dev.a.com
  • https://localhost
  • http://staging.a.com:5000
  • ...

We don't have to add them one by one, we can use regular expressions :)

For example, the rule for my blog website is this:

<rule name="Prevent Image Hotlinking">
  <match url=".*\.(gif|jpg|png)$"/>
  <conditions>
    <add input="{HTTP_REFERER}" pattern="^$" negate="true"/>
    <add input="{HTTP_REFERER}" pattern="^https?:\/\/.*edi.wang:?\d{0,5}?\/.*$" negate="true"/>
    <add input="{HTTP_REFERER}" pattern="^https?:\/\/localhost:?\d{0,5}?\/.*$" negate="true"/>
    <add input="{HTTP_REFERER}" pattern="^https?:\/\/.*azurewebsites.net:?\d{0,5}?\/.*$" negate="true"/>
  </conditions>
  <action type="Rewrite" url="/images/no_hotlinking.png"/>
</rule>