Created
November 14, 2012 23:01
-
-
Save apeckham/4075469 to your computer and use it in GitHub Desktop.
Rack middleware to return a 403 if the referer is invalid
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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