0

Title pretty much says it all. I want to be able to record when an image is being hotlinked and the IP address which made the request. Is this perhaps a rack task?

Eric Norcross
  • 4,177
  • 4
  • 28
  • 53

1 Answers1

2

It is not the recommended practice to serve static assets from the production Rails server. This puts overhead processing on the server that is more easily handled by something like a reverse proxy with nginx. You can also use nginx to stop hotlinking exactly as you requested:

location ~* \.(gif|png|jpe?g)$ {
  expires 7d;
  add_header Pragma public;
  add_header Cache-Control "public, must-revalidate, proxy-revalidate";

  # prevent hotlink
  valid_referers none blocked ~.google. ~.bing. ~.yahoo. server_names ~($host);
  if ($invalid_referer) {
    rewrite (.*) /static/images/hotlink-denied.jpg redirect;
    # drop the 'redirect' flag for redirect without URL change (internal rewrite)
  }
}

# stop hotlink loop
location = /static/images/hotlink-denied.jpg { }

Assuming that you are unable to run a proxy in front of Rails, then you are on the right path thinking of Rack. Static assets are served by the ActionDispatch::Static Rack middleware, and this processing is done before the request is handed off to the application. Therefore, you could write your own Rack middleware and insert it before the ActionDispatch::Static middleware in your config/application.rb:

config.middleware.insert_before "ActionDispatch::Static", "MyMiddleware"

All that might be overkill, though. If you are dead-set on using Rails to serve static images, then you can put a very simple controller in place to serve images that looks at request.referer and put the logic to block hotlinking in the controller:

class HotlinkController < ApplicationController
  def show
    # Insert your logic here to check `request.referer' to ensure the request is permitted
    filename = params[:filename]
    send_file "public/images/#{filename}.jpg", type: 'image/jpg', disposition: 'inline'
  end
end

This would be the preferred method, as your custom Rack middleware will be invoked on every request the server receives, even those not for static assets, versus doing referrer checking only for requests for images.

anothermh
  • 9,815
  • 3
  • 33
  • 52