diff --git a/rack-protection/lib/rack/protection/authenticity_token.rb b/rack-protection/lib/rack/protection/authenticity_token.rb index c4a533d9..124d5e8f 100644 --- a/rack-protection/lib/rack/protection/authenticity_token.rb +++ b/rack-protection/lib/rack/protection/authenticity_token.rb @@ -16,10 +16,10 @@ module Rack class AuthenticityToken < Base def accepts?(env) return true if safe? env - request = Request.new env + session = session env token = session[:csrf] ||= session['_csrf_token'] || random_string env['HTTP_X_CSRF_TOKEN'] == token or - request.params['authenticity_token'] == token + Request.new(env).params['authenticity_token'] == token end end end diff --git a/rack-protection/lib/rack/protection/base.rb b/rack-protection/lib/rack/protection/base.rb index b17a5ffe..0388d06b 100644 --- a/rack-protection/lib/rack/protection/base.rb +++ b/rack-protection/lib/rack/protection/base.rb @@ -1,4 +1,5 @@ require 'rack/protection' +require 'digest' require 'logger' require 'uri' @@ -6,8 +7,9 @@ module Rack module Protection class Base DEFAULT_OPTIONS = { - :reaction => :default_reaction, :logging => true, :status => 403, - :message => 'Forbidden' + :reaction => :default_reaction, :logging => true, + :message => 'Forbidden', :encryptor => Digest::SHA1, + :session_key => 'rack.session', :status => 403 } attr_reader :app, :options @@ -55,8 +57,17 @@ module Rack [options[:status], {'Content-Type' => 'text/plain'}, [options[:message]]] end + def session?(env) + env.include? options[:session_key] + end + def session(env) - env['rack.session'] ||= {} + return env[options[:session_key]] if session? env + fail "you need to set up a session middleware *before* #{self.class}" + end + + def drop_session(env) + session(env).clear if session? env end def referrer(env) @@ -70,13 +81,13 @@ module Rack random_string false end - def drop_session(env) - env['rack.session'] = {} - end - def default_reaction(env) fail "no default reaction given for #{self.class}" end + + def encrypt(value) + options[:encryptor].hexdigest value.to_s + end end end end diff --git a/rack-protection/lib/rack/protection/session_hijacking.rb b/rack-protection/lib/rack/protection/session_hijacking.rb index b3b3d2b6..379a67c0 100644 --- a/rack-protection/lib/rack/protection/session_hijacking.rb +++ b/rack-protection/lib/rack/protection/session_hijacking.rb @@ -14,6 +14,24 @@ module Rack # # Not Yet Implemented! class SessionHijacking < Base + default_options :tracking_key => :tracking, :encrypt_tracking => true, + :track => %w[HTTP_USER_AGENT HTTP_ACCEPT_ENCODING HTTP_ACCEPT_LANGUAGE + HTTP_VERSION] + + def accepts?(env) + session = session env + key = options[:tracking_key] + if session.include? key + session[key].all? { |k,v| env[k] == encrypt(v) } + else + session[key] = {} + options[:track].each { |k| session[k] = encrypt(env[k]) } + end + end + + def encrypt(value) + options[:encrypt_tracking] ? super(value) : value.to_s + end end end end diff --git a/rack-protection/spec/spec_helper.rb b/rack-protection/spec/spec_helper.rb index c39c4b4a..1b7a9603 100644 --- a/rack-protection/spec/spec_helper.rb +++ b/rack-protection/spec/spec_helper.rb @@ -20,9 +20,18 @@ module TestHelpers end def mock_app(app = nil, &block) - app = block if app.nil? and block.arity == 1 - app = app ? Rack::Head.new(described_class.new(app)) : Rack::Builder.new(&block).to_app - @app = Rack::Lint.new(app) + app = block if app.nil? and block.arity == 1 + if app + klass = described_class + mock_app do + use Rack::Head + use Rack::Session::Cookie + use klass + run app + end + else + @app = Rack::Lint.new Rack::Builder.new(&block).to_app + end end def with_headers(headers) @@ -89,6 +98,8 @@ shared_examples_for 'any rack application' do end mock_app do + use Rack::Head + use Rack::Session::Cookie use detector use klass run DummyApp @@ -114,6 +125,8 @@ shared_examples_for 'any rack application' do end mock_app do + use Rack::Head + use Rack::Session::Cookie use detector use klass use changer