Skip to content

Instantly share code, notes, and snippets.

@apeckham
Created November 14, 2012 23:01
Show Gist options
  • Save apeckham/4075469 to your computer and use it in GitHub Desktop.
Save apeckham/4075469 to your computer and use it in GitHub Desktop.
Rack middleware to return a 403 if the referer is invalid
class RefererFilter
ALLOWED_HOSTS = Set.new(%w(
example.com
localhost
))
def initialize(app)
@app = app
end
def call(env)
if valid_referer(env['HTTP_REFERER'])
@app.call(env)
else
forbidden
end
end
private
def forbidden
[403, {"Content-Type" => "text/plain"}, ["Forbidden based on referer"]]
end
def valid_referer(header)
return false unless header
uri = URI.parse(header) rescue nil
return false unless uri
ALLOWED_HOSTS.include?(uri.host)
end
end
describe RefererFilter do
include Rack::Test::Methods
def app
Rack::Builder.app {
use RefererFilter
run lambda { |env| [200, {"Content-Type" => "text/html"}, []] }
}
end
it "requires example to be present in the referer" do
response_for_referer("http://yahoo.com").status.should == 403
end
it "requires localhost to be present in the referer" do
response_for_referer("http://localhost:8000").status.should == 200
end
it "requires example.com to be present in the referer" do
response_for_referer("http://asdf.example.com").status.should == 200
end
it "requires *.local to be present in the referer" do
response_for_referer("http://asdf.local").status.should == 200
end
it "requires example.tv to be present in the referer" do
response_for_referer("http://asdf.example.tv").status.should == 200
end
it "requires www.example.com to be present in the referer" do
response_for_referer("http://www.example.com").status.should == 200
end
it "requires a referer" do
response_for_referer(nil).status.should == 403
end
it "is OK with non-URL referers" do
response_for_referer("!! NOT_A_URL !!").status.should == 403
end
it "sets the content-type" do
response_for_referer("").headers["Content-Type"].should == "text/plain"
end
it "requires example in the host, not the path" do
response_for_referer("http://yahoo.com/example").status.should == 403
end
def response_for_referer(referer)
get "/", nil, "HTTP_REFERER" => referer
last_response
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment