Forum Moderators: open

Message Too Old, No Replies

How to block hotlinking with IIS

can this be done?

         

sullen

9:47 am on May 1, 2003 (gmt 0)

10+ Year Member



Question as title really.

How can I block people hotlinking to images with a Windows server? (doesn't actually have to be a block, just an auto-redirect to a page containing the image if necessary)

Dreamquick

2:20 pm on May 1, 2003 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



I asked a similar question recently but didn't get any good answers so I thought I'd share what I'd figured out so far;

If you are able to use .htaccess you're laughing because blocking hotlinkers using that is relatively simple.

However under IIS there seems to be two routes;

Use a 3rd party ISAPI filter, obviously this is a case of install and be problem free but I doubt they are cheap and they would also require access to the server which rules out shared hosts.

Use server-side scripting. There are a number of ways to do this, and I'm pretty sure it's possible to make a decent script which integrates seemlessly as far as the end user is concerned. Plus side is that it'll work with any hosting package, the downside is that it needs to be coded in the first place and obviously it would require some changes to directory paths to enable the scripting to intercept the call.

I'm intending to give the server-side option a try shortly so I'll probably have more to say on the subject then.

- Tony

sullen

6:42 pm on May 1, 2003 (gmt 0)

10+ Year Member



Server side scripting was something I had in mind too.

I was planning to somehow get the ASP session to kick in when an image is hit (rather than just an asp page as is the default) and then use the session_onStart subroutine in global.asa to redirect the user (if the page is a picture).

Was that your idea? If so do you know if it's as simple as associating jpg. and gif files with asp.dll? Would the server overheads be too high?

Of course another alternative would be to store all pictures as BLOBS in the database, but I really don't want to do that!

Dreamquick

7:37 pm on May 1, 2003 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



jpg. and gif files with asp.dll?

Nope I'm on a shared server and they don't let me play with stuff like that :(

Hardcore Code

Move the images you want protect to a non-webroot directory, this means that any request for them trips a 404. Modify your custom 404 to run custom code for any missing images before descends into the normal 404 handling stuff.

The custom code checks two things;

  • Do we have a copy of this image in the non-webroot directory? If not we can't do anything so jump back into the 404 code.
  • Do we think we want to serve this image to this user based on various factors?

If we want to serve the image then read the image from disk and write to the browser, otherwise either serve the "no hotlinking" image or redirect them to another image. Since the resources aren't ASP pages the 404 script will not be exposed by IIS and so to the end user it just appears as if they are accessing an image.

The obvious advantage is that there is no way around this security short of messing with some very low level HTTP headers - the actual image is never exposed and the only way to get to it lies within server side code.

The downside is that I'm not sure what impact this would have with larger images - the OS will cache the file so the drive impact will be negligible but I'm more interested in CPU usage and also response times.

Like I said I want try it out so I'll let you know.

- Tony

GaryK

8:19 pm on May 1, 2003 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



I tried this method once on a website that averaged around 1,500 unique visitors per day. My host at the time wound up asking me to remove it because it was a CPU and RAM hog.

However later on I read a tutorial on one of those ASP helpsites (4GuysFromRolla.com) about using this exact method to do something similar.

So, I'll be interested in seeing what your results are. Just thought you'd like to know you've got at least one other person who's interested in your experiment. :)

Dreamquick

5:59 pm on May 6, 2003 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



Well I've spent several days of head scratching (for the love of %deity% why didn't they just support binary reading in the file system object?) on the problem and then a random search on a two year old MSDN install hits the jackpot;

nb I only found this last night, but it appears to be just as fast as referencing the image itself when working with smaller images - no idea of overheads yet, or the impact with larger images.

Also on the good news front it only needs ASP and ADO. Thought I'd share to keep the thread open a while longer and to see if anyone else wants to comment if they have used this method before.

<%
Option Explicit

Dim sPath

Const adTypeBinary = 1

'Set the content type to the specific type that you are sending.
Response.ContentType = "image/gif"

'This is the path to the file on disk.
sPath= Server.MapPath( "imgsrv.gif" )

Set objStream = Server.CreateObject("ADODB.Stream")
objStream.Open
objStream.Type = adTypeBinary
objStream.LoadFromFile sPath

Response.BinaryWrite objStream.Read

objStream.Close
Set objStream = Nothing
%>

- Tony

sullen

6:58 pm on May 6, 2003 (gmt 0)

10+ Year Member



Oh yeah!

That looks like just the kind of thing that would work. Do let us know if you find any nasty gotchas / server issues or the like won't you.

Dreamquick

9:19 pm on May 7, 2003 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



I ran a few tests with the posted script, a 400k image and w2k's performance monitor. Tracked a few variables (couple of ASP queuing events & CPU usage) and there was no noticable difference between serving a regular image and having the image proxied by ASP.

In all honesty if you didn't know it was being proxied by an ASP page you'd swear you were getting the real image firsthand.

Sadly I don't have decent access to my host so I can't tell you what the overall effect is on a live server w/ PerfMon. Those initial PerfMon tests were on my LAN as this way I would be able to differentiate slow server and poor connection.

I've transferred a copy of it onto my hosting space for a small-scale test - so far it blocks one or two hotlinkers causing me grief & is almost invisible so I'm happy.

Once I'm convinced this version is working I'll post some enhanced code.

- Tony