Blocking external image linking with Web Server 6 and 6.1
By jmccabe on May 19, 2006
A few years ago I noticed that I was spending a huge amount of bandwidth on particular images in my URI space. Some investigation through the Referer fields showed me that the images were being embedded on a popular sports forum, and every time a thread was displayed my server server had to spend energy and bandwidth providing the images. Naturally this really annoyed me. After considering the problem for a few minutes Chris and I came up with a solution that allows me to block all requests for images that did not get linked to from my local server.
This snippet of my obj.conf would be placed at the default object. Comments are inline.
# People are direct-linking to images. # To kill these requests I need to abort the request, but only if it # contains a Referer header and that the Referer is not from one of my # local Virtual Servers. # The <Client ...> tag is used to make the execution of the # "Don't Do This" NameTrans conditional. The "uri=..." part looks # for the URI strings that I want scrutinized. The two "headers ..." # check that there is a Referer header, and that the header does not # contain the Host name of one of my local Virtual Servers. Web Server 7 # will make this easier with much more versatile regular expression and # variable support here. <Client uri="\*.(gif|GIF|png|PNG|jpg|JPG)\*" headers="Referer: ?\*" headers="Referer: \*~\*(foo.org|bar.com|baz.com)\*"> # This is our NameTrans that aborts the request. "abort=true" stops our # processing of the request, and "error=###" sends that HTTP status code # to the User-Agent. NameTrans fn=set-variable abort="true" error="412" </Client>
So this will just throw a 412 to the User-Agent, log it, and move on. This is fine for just not wanted to deal with things, but I found that I wanted to be able to host my own images in other people's blogs without my server panicking. I found that I also didn't like returning a simple HTTP error with explanatory HTML since the User-Agent will not display it. I found it more entertaining to return my own image explaining that direct-linking to images is rude. So the solution evolved to:
# Notice that "~/export_images/\*" has been added to the end of the URI # string. This basically means "but" or "except" and will match the # URI string match unless it also contains this string. <Client uri="\*.(gif|GIF|png|PNG|jpg|JPG)\*~/export_images/\*" headers="Referer: ?\*" headers="Referer: \*~\*(foo.org|bar.com|baz.com)\*"> # I've changed to a "302" (temporary redirect) and provided a URL # for my "you did a bad thing" image that lives in my export directory. NameTrans fn=set-variable abort="true" error="302" set-srvhdrs="Location: http://www.foo.org/export_images/direct.png" </Client>
A fringe benefit to this is that whoever did the direct link will have locally cached the image from when they were hunting for it. Once they provide their direct link in their blog or forum entry, their browser will show the correct image out of the local cache. All the visitors to their blog or forum entry will see the alternative "you did a bad thing" image. Hilarity ensues.
So - The first solution creates broken image icons in their web pages, the second solution uses a little more bandwidth but allows you to explain to them your thoughts on the practice of direct linking.