Permalink
Browse files

Merge pull request #16 from p0deje/http_origin

Implementation of Origin CSRF mitigation request header
  • Loading branch information...
2 parents cddd6db + 92ab5dd commit f1c8b5562178c6e6474ea34aa23092c351150465 @rkh rkh committed May 12, 2012
Showing with 74 additions and 0 deletions.
  1. +1 −0 README.md
  2. +2 −0 lib/rack/protection.rb
  3. +32 −0 lib/rack/protection/http_origin.rb
  4. +39 −0 spec/http_origin_spec.rb
View
@@ -43,6 +43,7 @@ Prevented by:
* `Rack::Protection::JsonCsrf`
* `Rack::Protection::RemoteReferrer` (not included by `use Rack::Protection`)
* `Rack::Protection::RemoteToken`
+* `Rack::Protection::HttpOrigin`
## Cross Site Scripting
View
@@ -8,6 +8,7 @@ module Protection
autoload :EscapedParams, 'rack/protection/escaped_params'
autoload :FormToken, 'rack/protection/form_token'
autoload :FrameOptions, 'rack/protection/frame_options'
+ autoload :HttpOrigin, 'rack/protection/http_origin'
autoload :IPSpoofing, 'rack/protection/ip_spoofing'
autoload :JsonCsrf, 'rack/protection/json_csrf'
autoload :PathTraversal, 'rack/protection/path_traversal'
@@ -21,6 +22,7 @@ def self.new(app, options = {})
except = Array options[:except]
Rack::Builder.new do
use ::Rack::Protection::FrameOptions, options unless except.include? :frame_options
+ use ::Rack::Protection::HttpOrigin, options unless except.include? :http_origin
use ::Rack::Protection::IPSpoofing, options unless except.include? :ip_spoofing
use ::Rack::Protection::JsonCsrf, options unless except.include? :json_csrf
use ::Rack::Protection::PathTraversal, options unless except.include? :path_traversal
@@ -0,0 +1,32 @@
+require 'rack/protection'
+
+module Rack
+ module Protection
+ ##
+ # Prevented attack:: CSRF
+ # Supported browsers:: Google Chrome 2, Safari 4 and later
+ # More infos:: http://en.wikipedia.org/wiki/Cross-site_request_forgery
+ # http://tools.ietf.org/html/draft-abarth-origin
+ #
+ # Does not accept unsafe HTTP requests when value of Origin HTTP request header
+ # does not match default or whitelisted URIs.
+ class HttpOrigin < Base
+ default_reaction :deny
+
+ def accepts?(env)
+ # only for unsafe request methods
+ safe?(env) and return true
+ # ignore if origin is not set
+ origin = env['HTTP_ORIGIN'] or return true
+
+ # check base url
+ Request.new(env).base_url == origin and return true
+
+ # check whitelist
+ options[:origin_whitelist] or return false
+ options[:origin_whitelist].include?(origin)
+ end
+
+ end
+ end
+end
View
@@ -0,0 +1,39 @@
+require File.expand_path('../spec_helper.rb', __FILE__)
+
+describe Rack::Protection::HttpOrigin do
+ it_behaves_like "any rack application"
+
+ %w(GET HEAD POST PUT DELETE).each do |method|
+ it "accepts #{method} requests with no Origin" do
+ send(method.downcase, '/').should be_ok
+ end
+ end
+
+ %w(GET HEAD).each do |method|
+ it "accepts #{method} requests with non-whitelisted Origin" do
+ mock_app do
+ use Rack::Protection::HttpOrigin
+ run DummyApp
+ end
+ send(method.downcase, '/', {}, 'HTTP_ORIGIN' => 'http://malicious.com').should be_ok
+ end
+ end
+
+ %w(POST PUT DELETE).each do |method|
+ it "denies #{method} requests with non-whitelisted Origin" do
+ mock_app do
+ use Rack::Protection::HttpOrigin
+ run DummyApp
+ end
+ send(method.downcase, '/', {}, 'HTTP_ORIGIN' => 'http://malicious.com').should_not be_ok
+ end
+
+ it "accepts #{method} requests with whitelisted Origin" do
+ mock_app do
+ use Rack::Protection::HttpOrigin, :origin_whitelist => ['http://www.friend.com']
+ run DummyApp
+ end
+ send(method.downcase, '/', {}, 'HTTP_ORIGIN' => 'http://www.friend.com').should be_ok
+ end
+ end
+end

0 comments on commit f1c8b55

Please sign in to comment.