rack-protection-1.5.3/0000755000004100000410000000000012325252405014654 5ustar www-datawww-datarack-protection-1.5.3/Rakefile0000644000004100000410000000250412325252405016322 0ustar www-datawww-data# encoding: utf-8 $LOAD_PATH.unshift File.expand_path('../lib', __FILE__) begin require 'bundler' Bundler::GemHelper.install_tasks rescue LoadError => e $stderr.puts e end desc "run specs" task(:spec) { ruby '-S rspec spec' } desc "generate gemspec" task 'rack-protection.gemspec' do require 'rack/protection/version' content = File.binread 'rack-protection.gemspec' # fetch data fields = { :authors => `git shortlog -sn`.force_encoding('utf-8').scan(/[^\d\s].*/), :email => `git shortlog -sne`.force_encoding('utf-8').scan(/[^<]+@[^>]+/), :files => `git ls-files`.force_encoding('utf-8').split("\n").reject { |f| f =~ /^(\.|Gemfile)/ } } # double email :( fields[:email].delete("konstantin.haase@gmail.com") # insert data fields.each do |field, values| updated = " s.#{field} = [" updated << values.map { |v| "\n %p" % v }.join(',') updated << "\n ]" content.sub!(/ s\.#{field} = \[\n( .*\n)* \]/, updated) end # set version content.sub! /(s\.version.*=\s+).*/, "\\1\"#{Rack::Protection::VERSION}\"" # escape unicode content.gsub!(/./) { |c| c.bytesize > 1 ? "\\u{#{c.codepoints.first.to_s(16)}}" : c } File.open('rack-protection.gemspec', 'w') { |f| f << content } end task :gemspec => 'rack-protection.gemspec' task :default => :spec task :test => :spec rack-protection-1.5.3/spec/0000755000004100000410000000000012325252405015606 5ustar www-datawww-datarack-protection-1.5.3/spec/ip_spoofing_spec.rb0000644000004100000410000000233412325252405021463 0ustar www-datawww-datarequire File.expand_path('../spec_helper.rb', __FILE__) describe Rack::Protection::IPSpoofing do it_behaves_like "any rack application" it 'accepts requests without X-Forward-For header' do get('/', {}, 'HTTP_CLIENT_IP' => '1.2.3.4', 'HTTP_X_REAL_IP' => '4.3.2.1') last_response.should be_ok end it 'accepts requests with proper X-Forward-For header' do get('/', {}, 'HTTP_CLIENT_IP' => '1.2.3.4', 'HTTP_X_FORWARDED_FOR' => '192.168.1.20, 1.2.3.4, 127.0.0.1') last_response.should be_ok end it 'denies requests where the client spoofs X-Forward-For but not the IP' do get('/', {}, 'HTTP_CLIENT_IP' => '1.2.3.4', 'HTTP_X_FORWARDED_FOR' => '1.2.3.5') last_response.should_not be_ok end it 'denies requests where the client spoofs the IP but not X-Forward-For' do get('/', {}, 'HTTP_CLIENT_IP' => '1.2.3.5', 'HTTP_X_FORWARDED_FOR' => '192.168.1.20, 1.2.3.4, 127.0.0.1') last_response.should_not be_ok end it 'denies requests where IP and X-Forward-For are spoofed but not X-Real-IP' do get('/', {}, 'HTTP_CLIENT_IP' => '1.2.3.5', 'HTTP_X_FORWARDED_FOR' => '1.2.3.5', 'HTTP_X_REAL_IP' => '1.2.3.4') last_response.should_not be_ok end end rack-protection-1.5.3/spec/frame_options_spec.rb0000644000004100000410000000241412325252405022013 0ustar www-datawww-datarequire File.expand_path('../spec_helper.rb', __FILE__) describe Rack::Protection::FrameOptions do it_behaves_like "any rack application" it 'should set the X-Frame-Options' do get('/', {}, 'wants' => 'text/html').headers["X-Frame-Options"].should == "SAMEORIGIN" end it 'should not set the X-Frame-Options for other content types' do get('/', {}, 'wants' => 'text/foo').headers["X-Frame-Options"].should be_nil end it 'should allow changing the protection mode' do # I have no clue what other modes are available mock_app do use Rack::Protection::FrameOptions, :frame_options => :deny run DummyApp end get('/', {}, 'wants' => 'text/html').headers["X-Frame-Options"].should == "DENY" end it 'should allow changing the protection mode to a string' do # I have no clue what other modes are available mock_app do use Rack::Protection::FrameOptions, :frame_options => "ALLOW-FROM foo" run DummyApp end get('/', {}, 'wants' => 'text/html').headers["X-Frame-Options"].should == "ALLOW-FROM foo" end it 'should not override the header if already set' do mock_app with_headers("X-Frame-Options" => "allow") get('/', {}, 'wants' => 'text/html').headers["X-Frame-Options"].should == "allow" end end rack-protection-1.5.3/spec/json_csrf_spec.rb0000644000004100000410000000350612325252405021137 0ustar www-datawww-datarequire File.expand_path('../spec_helper.rb', __FILE__) describe Rack::Protection::JsonCsrf do it_behaves_like "any rack application" describe 'json response' do before do mock_app { |e| [200, {'Content-Type' => 'application/json'}, []]} end it "denies get requests with json responses with a remote referrer" do get('/', {}, 'HTTP_REFERER' => 'http://evil.com').should_not be_ok end it "accepts requests with json responses with a remote referrer when there's an origin header set" do get('/', {}, 'HTTP_REFERER' => 'http://good.com', 'HTTP_ORIGIN' => 'http://good.com').should be_ok end it "accepts requests with json responses with a remote referrer when there's an x-origin header set" do get('/', {}, 'HTTP_REFERER' => 'http://good.com', 'HTTP_X_ORIGIN' => 'http://good.com').should be_ok end it "accepts get requests with json responses with a local referrer" do get('/', {}, 'HTTP_REFERER' => '/').should be_ok end it "accepts get requests with json responses with no referrer" do get('/', {}).should be_ok end it "accepts XHR requests" do get('/', {}, 'HTTP_REFERER' => 'http://evil.com', 'HTTP_X_REQUESTED_WITH' => 'XMLHttpRequest').should be_ok end end describe 'not json response' do it "accepts get requests with 304 headers" do mock_app { |e| [304, {}, []]} get('/', {}).status.should == 304 end end describe 'with drop_session as default reaction' do it 'still denies' do mock_app do use Rack::Protection, :reaction => :drop_session run proc { |e| [200, {'Content-Type' => 'application/json'}, []]} end session = {:foo => :bar} get('/', {}, 'HTTP_REFERER' => 'http://evil.com', 'rack.session' => session) last_response.should_not be_ok end end end rack-protection-1.5.3/spec/spec_helper.rb0000644000004100000410000000741112325252405020427 0ustar www-datawww-datarequire 'rack/protection' require 'rack/test' require 'rack' require 'forwardable' require 'stringio' if defined? Gem.loaded_specs and Gem.loaded_specs.include? 'rack' version = Gem.loaded_specs['rack'].version.to_s else version = Rack.release + '.0' end if version == "1.3" Rack::Session::Abstract::ID.class_eval do private def prepare_session(env) session_was = env[ENV_SESSION_KEY] env[ENV_SESSION_KEY] = SessionHash.new(self, env) env[ENV_SESSION_OPTIONS_KEY] = OptionsHash.new(self, env, @default_options) env[ENV_SESSION_KEY].merge! session_was if session_was end end end unless Rack::MockResponse.method_defined? :header Rack::MockResponse.send(:alias_method, :header, :headers) end module DummyApp def self.call(env) Thread.current[:last_env] = env body = (env['REQUEST_METHOD'] == 'HEAD' ? '' : 'ok') [200, {'Content-Type' => env['wants'] || 'text/plain'}, [body]] end end module TestHelpers extend Forwardable def_delegators :last_response, :body, :headers, :status, :errors def_delegators :current_session, :env_for attr_writer :app def app @app || mock_app(DummyApp) end def mock_app(app = nil, &block) app = block if app.nil? and block.arity == 1 if app klass = described_class mock_app do use Rack::Head use(Rack::Config) { |e| e['rack.session'] ||= {}} use klass run app end else @app = Rack::Lint.new Rack::Builder.new(&block).to_app end end def with_headers(headers) proc { [200, {'Content-Type' => 'text/plain'}.merge(headers), ['ok']] } end def env Thread.current[:last_env] end end # see http://blog.101ideas.cz/posts/pending-examples-via-not-implemented-error-in-rspec.html module NotImplementedAsPending def self.included(base) base.class_eval do alias_method :__finish__, :finish remove_method :finish end end def finish(reporter) if @exception.is_a?(NotImplementedError) from = @exception.backtrace[0] message = "#{@exception.message} (from #{from})" @pending_declared_in_example = message metadata[:pending] = true @exception = nil end __finish__(reporter) end RSpec::Core::Example.send :include, self end RSpec.configure do |config| config.expect_with :rspec, :stdlib config.include Rack::Test::Methods config.include TestHelpers end shared_examples_for 'any rack application' do it "should not interfere with normal get requests" do get('/').should be_ok body.should == 'ok' end it "should not interfere with normal head requests" do head('/').should be_ok end it 'should not leak changes to env' do klass = described_class detector = Struct.new(:app) detector.send(:define_method, :call) do |env| was = env.dup res = app.call(env) was.each do |k,v| next if env[k] == v fail "env[#{k.inspect}] changed from #{v.inspect} to #{env[k].inspect}" end res end mock_app do use Rack::Head use(Rack::Config) { |e| e['rack.session'] ||= {}} use detector use klass run DummyApp end get('/..', :foo => '').should be_ok end it 'allows passing on values in env' do klass = described_class detector = Struct.new(:app) changer = Struct.new(:app) detector.send(:define_method, :call) do |env| res = app.call(env) env['foo.bar'].should == 42 res end changer.send(:define_method, :call) do |env| env['foo.bar'] = 42 app.call(env) end mock_app do use Rack::Head use(Rack::Config) { |e| e['rack.session'] ||= {}} use detector use klass use changer run DummyApp end get('/').should be_ok end end rack-protection-1.5.3/spec/remote_referrer_spec.rb0000644000004100000410000000172712325252405022343 0ustar www-datawww-datarequire File.expand_path('../spec_helper.rb', __FILE__) describe Rack::Protection::RemoteReferrer do it_behaves_like "any rack application" it "accepts post requests with no referrer" do post('/').should be_ok end it "does not accept post requests with no referrer if allow_empty_referrer is false" do mock_app do use Rack::Protection::RemoteReferrer, :allow_empty_referrer => false run DummyApp end post('/').should_not be_ok end it "should allow post request with a relative referrer" do post('/', {}, 'HTTP_REFERER' => '/').should be_ok end it "accepts post requests with the same host in the referrer" do post('/', {}, 'HTTP_REFERER' => 'http://example.com/foo', 'HTTP_HOST' => 'example.com') last_response.should be_ok end it "denies post requests with a remote referrer" do post('/', {}, 'HTTP_REFERER' => 'http://example.com/foo', 'HTTP_HOST' => 'example.org') last_response.should_not be_ok end end rack-protection-1.5.3/spec/http_origin_spec.rb0000644000004100000410000000216012325252405021472 0ustar www-datawww-datarequire File.expand_path('../spec_helper.rb', __FILE__) describe Rack::Protection::HttpOrigin do it_behaves_like "any rack application" before(:each) do mock_app do use Rack::Protection::HttpOrigin run DummyApp end end %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 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 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 rack-protection-1.5.3/spec/path_traversal_spec.rb0000644000004100000410000000256412325252405022173 0ustar www-datawww-datarequire File.expand_path('../spec_helper.rb', __FILE__) describe Rack::Protection::PathTraversal do it_behaves_like "any rack application" context 'escaping' do before do mock_app { |e| [200, {'Content-Type' => 'text/plain'}, [e['PATH_INFO']]] } end %w[/foo/bar /foo/bar/ / /.f /a.x].each do |path| it("does not touch #{path.inspect}") { get(path).body.should == path } end { # yes, this is ugly, feel free to change that '/..' => '/', '/a/../b' => '/b', '/a/../b/' => '/b/', '/a/.' => '/a/', '/%2e.' => '/', '/a/%2E%2e/b' => '/b', '/a%2f%2E%2e%2Fb/' => '/b/', '//' => '/', '/%2fetc%2Fpasswd' => '/etc/passwd' }.each do |a, b| it("replaces #{a.inspect} with #{b.inspect}") { get(a).body.should == b } end it 'should be able to deal with PATH_INFO = nil (fcgi?)' do app = Rack::Protection::PathTraversal.new(proc { 42 }) app.call({}).should be == 42 end end if "".respond_to?(:encoding) # Ruby 1.9+ M17N context "PATH_INFO's encoding" do before do @app = Rack::Protection::PathTraversal.new(proc { |e| [200, {'Content-Type' => 'text/plain'}, [e['PATH_INFO'].encoding.to_s]] }) end it 'should remain unchanged as ASCII-8BIT' do body = @app.call({ 'PATH_INFO' => '/'.encode('ASCII-8BIT') })[2][0] body.should == 'ASCII-8BIT' end end end end rack-protection-1.5.3/spec/authenticity_token_spec.rb0000644000004100000410000000314312325252405023060 0ustar www-datawww-datarequire File.expand_path('../spec_helper.rb', __FILE__) describe Rack::Protection::AuthenticityToken do it_behaves_like "any rack application" it "denies post requests without any token" do post('/').should_not be_ok end it "accepts post requests with correct X-CSRF-Token header" do post('/', {}, 'rack.session' => {:csrf => "a"}, 'HTTP_X_CSRF_TOKEN' => "a") last_response.should be_ok end it "denies post requests with wrong X-CSRF-Token header" do post('/', {}, 'rack.session' => {:csrf => "a"}, 'HTTP_X_CSRF_TOKEN' => "b") last_response.should_not be_ok end it "accepts post form requests with correct authenticity_token field" do post('/', {"authenticity_token" => "a"}, 'rack.session' => {:csrf => "a"}) last_response.should be_ok end it "denies post form requests with wrong authenticity_token field" do post('/', {"authenticity_token" => "a"}, 'rack.session' => {:csrf => "b"}) last_response.should_not be_ok end it "prevents ajax requests without a valid token" do post('/', {}, "HTTP_X_REQUESTED_WITH" => "XMLHttpRequest").should_not be_ok end it "allows for a custom authenticity token param" do mock_app do use Rack::Protection::AuthenticityToken, :authenticity_param => 'csrf_param' run proc { |e| [200, {'Content-Type' => 'text/plain'}, ['hi']] } end post('/', {"csrf_param" => "a"}, 'rack.session' => {:csrf => "a"}) last_response.should be_ok end it "sets a new csrf token for the session in env, even after a 'safe' request" do get('/', {}, {}) env['rack.session'][:csrf].should_not be_nil end end rack-protection-1.5.3/spec/base_spec.rb0000644000004100000410000000241312325252405020057 0ustar www-datawww-datarequire File.expand_path('../spec_helper.rb', __FILE__) describe Rack::Protection::Base do subject { described_class.new(lambda {}) } describe "#random_string" do it "outputs a string of 32 characters" do subject.random_string.length.should == 32 end end describe "#referrer" do it "Reads referrer from Referer header" do env = {"HTTP_HOST" => "foo.com", "HTTP_REFERER" => "http://bar.com/valid"} subject.referrer(env).should == "bar.com" end it "Reads referrer from Host header when Referer header is relative" do env = {"HTTP_HOST" => "foo.com", "HTTP_REFERER" => "/valid"} subject.referrer(env).should == "foo.com" end it "Reads referrer from Host header when Referer header is missing" do env = {"HTTP_HOST" => "foo.com"} subject.referrer(env).should == "foo.com" end it "Returns nil when Referer header is missing and allow_empty_referrer is false" do env = {"HTTP_HOST" => "foo.com"} subject.options[:allow_empty_referrer] = false subject.referrer(env).should be_nil end it "Returns nil when Referer header is invalid" do env = {"HTTP_HOST" => "foo.com", "HTTP_REFERER" => "http://bar.com/bad|uri"} subject.referrer(env).should be_nil end end end rack-protection-1.5.3/spec/session_hijacking_spec.rb0000644000004100000410000000405112325252405022637 0ustar www-datawww-datarequire File.expand_path('../spec_helper.rb', __FILE__) describe Rack::Protection::SessionHijacking do it_behaves_like "any rack application" it "accepts a session without changes to tracked parameters" do session = {:foo => :bar} get '/', {}, 'rack.session' => session get '/', {}, 'rack.session' => session session[:foo].should == :bar end it "denies requests with a changing User-Agent header" do session = {:foo => :bar} get '/', {}, 'rack.session' => session, 'HTTP_USER_AGENT' => 'a' get '/', {}, 'rack.session' => session, 'HTTP_USER_AGENT' => 'b' session.should be_empty end it "accepts requests with a changing Accept-Encoding header" do # this is tested because previously it led to clearing the session session = {:foo => :bar} get '/', {}, 'rack.session' => session, 'HTTP_ACCEPT_ENCODING' => 'a' get '/', {}, 'rack.session' => session, 'HTTP_ACCEPT_ENCODING' => 'b' session.should_not be_empty end it "denies requests with a changing Accept-Language header" do session = {:foo => :bar} get '/', {}, 'rack.session' => session, 'HTTP_ACCEPT_LANGUAGE' => 'a' get '/', {}, 'rack.session' => session, 'HTTP_ACCEPT_LANGUAGE' => 'b' session.should be_empty end it "accepts requests with the same Accept-Language header" do session = {:foo => :bar} get '/', {}, 'rack.session' => session, 'HTTP_ACCEPT_LANGUAGE' => 'a' get '/', {}, 'rack.session' => session, 'HTTP_ACCEPT_LANGUAGE' => 'a' session.should_not be_empty end it "comparison of Accept-Language header is not case sensitive" do session = {:foo => :bar} get '/', {}, 'rack.session' => session, 'HTTP_ACCEPT_LANGUAGE' => 'a' get '/', {}, 'rack.session' => session, 'HTTP_ACCEPT_LANGUAGE' => 'A' session.should_not be_empty end it "accepts requests with a changing Version header"do session = {:foo => :bar} get '/', {}, 'rack.session' => session, 'HTTP_VERSION' => '1.0' get '/', {}, 'rack.session' => session, 'HTTP_VERSION' => '1.1' session[:foo].should == :bar end end rack-protection-1.5.3/spec/remote_token_spec.rb0000644000004100000410000000324712325252405021646 0ustar www-datawww-datarequire File.expand_path('../spec_helper.rb', __FILE__) describe Rack::Protection::RemoteToken do it_behaves_like "any rack application" it "accepts post requests with no referrer" do post('/').should be_ok end it "accepts post requests with a local referrer" do post('/', {}, 'HTTP_REFERER' => '/').should be_ok end it "denies post requests with a remote referrer and no token" do post('/', {}, 'HTTP_REFERER' => 'http://example.com/foo', 'HTTP_HOST' => 'example.org') last_response.should_not be_ok end it "accepts post requests with a remote referrer and correct X-CSRF-Token header" do post('/', {}, 'HTTP_REFERER' => 'http://example.com/foo', 'HTTP_HOST' => 'example.org', 'rack.session' => {:csrf => "a"}, 'HTTP_X_CSRF_TOKEN' => "a") last_response.should be_ok end it "denies post requests with a remote referrer and wrong X-CSRF-Token header" do post('/', {}, 'HTTP_REFERER' => 'http://example.com/foo', 'HTTP_HOST' => 'example.org', 'rack.session' => {:csrf => "a"}, 'HTTP_X_CSRF_TOKEN' => "b") last_response.should_not be_ok end it "accepts post form requests with a remote referrer and correct authenticity_token field" do post('/', {"authenticity_token" => "a"}, 'HTTP_REFERER' => 'http://example.com/foo', 'HTTP_HOST' => 'example.org', 'rack.session' => {:csrf => "a"}) last_response.should be_ok end it "denies post form requests with a remote referrer and wrong authenticity_token field" do post('/', {"authenticity_token" => "a"}, 'HTTP_REFERER' => 'http://example.com/foo', 'HTTP_HOST' => 'example.org', 'rack.session' => {:csrf => "b"}) last_response.should_not be_ok end end rack-protection-1.5.3/spec/form_token_spec.rb0000644000004100000410000000213612325252405021312 0ustar www-datawww-datarequire File.expand_path('../spec_helper.rb', __FILE__) describe Rack::Protection::FormToken do it_behaves_like "any rack application" it "denies post requests without any token" do post('/').should_not be_ok end it "accepts post requests with correct X-CSRF-Token header" do post('/', {}, 'rack.session' => {:csrf => "a"}, 'HTTP_X_CSRF_TOKEN' => "a") last_response.should be_ok end it "denies post requests with wrong X-CSRF-Token header" do post('/', {}, 'rack.session' => {:csrf => "a"}, 'HTTP_X_CSRF_TOKEN' => "b") last_response.should_not be_ok end it "accepts post form requests with correct authenticity_token field" do post('/', {"authenticity_token" => "a"}, 'rack.session' => {:csrf => "a"}) last_response.should be_ok end it "denies post form requests with wrong authenticity_token field" do post('/', {"authenticity_token" => "a"}, 'rack.session' => {:csrf => "b"}) last_response.should_not be_ok end it "accepts ajax requests without a valid token" do post('/', {}, "HTTP_X_REQUESTED_WITH" => "XMLHttpRequest").should be_ok end end rack-protection-1.5.3/spec/xss_header_spec.rb0000644000004100000410000000362212325252405021275 0ustar www-datawww-datarequire File.expand_path('../spec_helper.rb', __FILE__) describe Rack::Protection::XSSHeader do it_behaves_like "any rack application" it 'should set the X-XSS-Protection' do get('/', {}, 'wants' => 'text/html;charset=utf-8').headers["X-XSS-Protection"].should == "1; mode=block" end it 'should set the X-XSS-Protection for XHTML' do get('/', {}, 'wants' => 'application/xhtml+xml').headers["X-XSS-Protection"].should == "1; mode=block" end it 'should not set the X-XSS-Protection for other content types' do get('/', {}, 'wants' => 'application/foo').headers["X-XSS-Protection"].should be_nil end it 'should allow changing the protection mode' do # I have no clue what other modes are available mock_app do use Rack::Protection::XSSHeader, :xss_mode => :foo run DummyApp end get('/', {}, 'wants' => 'application/xhtml').headers["X-XSS-Protection"].should == "1; mode=foo" end it 'should not override the header if already set' do mock_app with_headers("X-XSS-Protection" => "0") get('/', {}, 'wants' => 'text/html').headers["X-XSS-Protection"].should == "0" end it 'should set the X-Content-Type-Options' do get('/', {}, 'wants' => 'text/html').header["X-Content-Type-Options"].should == "nosniff" end it 'should set the X-Content-Type-Options for other content types' do get('/', {}, 'wants' => 'application/foo').header["X-Content-Type-Options"].should == "nosniff" end it 'should allow changing the nosniff-mode off' do mock_app do use Rack::Protection::XSSHeader, :nosniff => false run DummyApp end get('/').headers["X-Content-Type-Options"].should be_nil end it 'should not override the header if already set X-Content-Type-Options' do mock_app with_headers("X-Content-Type-Options" => "sniff") get('/', {}, 'wants' => 'text/html').headers["X-Content-Type-Options"].should == "sniff" end end rack-protection-1.5.3/spec/escaped_params_spec.rb0000644000004100000410000000224512325252405022117 0ustar www-datawww-datarequire File.expand_path('../spec_helper.rb', __FILE__) describe Rack::Protection::EscapedParams do it_behaves_like "any rack application" context 'escaping' do it 'escapes html entities' do mock_app do |env| request = Rack::Request.new(env) [200, {'Content-Type' => 'text/plain'}, [request.params['foo']]] end get '/', :foo => "" body.should == '<bar>' end it 'leaves normal params untouched' do mock_app do |env| request = Rack::Request.new(env) [200, {'Content-Type' => 'text/plain'}, [request.params['foo']]] end get '/', :foo => "bar" body.should == 'bar' end it 'copes with nested arrays' do mock_app do |env| request = Rack::Request.new(env) [200, {'Content-Type' => 'text/plain'}, [request.params['foo']['bar']]] end get '/', :foo => {:bar => ""} body.should == '<bar>' end it 'leaves cache-breaker params untouched' do mock_app do |env| [200, {'Content-Type' => 'text/plain'}, ['hi']] end get '/?95df8d9bf5237ad08df3115ee74dcb10' body.should == 'hi' end end end rack-protection-1.5.3/spec/protection_spec.rb0000755000004100000410000000650712325252405021346 0ustar www-datawww-datarequire File.expand_path('../spec_helper.rb', __FILE__) describe Rack::Protection do it_behaves_like "any rack application" it 'passes on options' do mock_app do use Rack::Protection, :track => ['HTTP_FOO'] run proc { |e| [200, {'Content-Type' => 'text/plain'}, ['hi']] } end session = {:foo => :bar} get '/', {}, 'rack.session' => session, 'HTTP_ACCEPT_ENCODING' => 'a' get '/', {}, 'rack.session' => session, 'HTTP_ACCEPT_ENCODING' => 'b' session[:foo].should be == :bar get '/', {}, 'rack.session' => session, 'HTTP_FOO' => 'BAR' session.should be_empty end it 'passes errors through if :reaction => :report is used' do mock_app do use Rack::Protection, :reaction => :report run proc { |e| [200, {'Content-Type' => 'text/plain'}, [e["protection.failed"].to_s]] } end session = {:foo => :bar} post('/', {}, 'rack.session' => session, 'HTTP_ORIGIN' => 'http://malicious.com') last_response.should be_ok body.should == "true" end describe "#react" do it 'prevents attacks and warns about it' do io = StringIO.new mock_app do use Rack::Protection, :logger => Logger.new(io) run DummyApp end post('/', {}, 'rack.session' => {}, 'HTTP_ORIGIN' => 'http://malicious.com') io.string.should match /prevented.*Origin/ end it 'reports attacks if reaction is to report' do io = StringIO.new mock_app do use Rack::Protection, :reaction => :report, :logger => Logger.new(io) run DummyApp end post('/', {}, 'rack.session' => {}, 'HTTP_ORIGIN' => 'http://malicious.com') io.string.should match /reported.*Origin/ io.string.should_not match /prevented.*Origin/ end it 'passes errors to reaction method if specified' do io = StringIO.new Rack::Protection::Base.send(:define_method, :special) { |*args| io << args.inspect } mock_app do use Rack::Protection, :reaction => :special, :logger => Logger.new(io) run DummyApp end post('/', {}, 'rack.session' => {}, 'HTTP_ORIGIN' => 'http://malicious.com') io.string.should match /HTTP_ORIGIN.*malicious.com/ io.string.should_not match /reported|prevented/ end end describe "#html?" do context "given an appropriate content-type header" do subject { Rack::Protection::Base.new(nil).html? 'content-type' => "text/html" } it { should be_true } end context "given an inappropriate content-type header" do subject { Rack::Protection::Base.new(nil).html? 'content-type' => "image/gif" } it { should be_false } end context "given no content-type header" do subject { Rack::Protection::Base.new(nil).html?({}) } it { should be_false } end end describe "#instrument" do let(:env) { { 'rack.protection.attack' => 'base' } } let(:instrumenter) { double('Instrumenter') } after do app.instrument(env) end context 'with an instrumenter specified' do let(:app) { Rack::Protection::Base.new(nil, :instrumenter => instrumenter) } it { instrumenter.should_receive(:instrument).with('rack.protection', env) } end context 'with no instrumenter specified' do let(:app) { Rack::Protection::Base.new(nil) } it { instrumenter.should_not_receive(:instrument) } end end end rack-protection-1.5.3/rack-protection.gemspec0000644000004100000410000000631212325252405021327 0ustar www-datawww-data# Run `rake rack-protection.gemspec` to update the gemspec. Gem::Specification.new do |s| # general infos s.name = "rack-protection" s.version = "1.5.3" s.description = "You should use protection!" s.homepage = "http://github.com/rkh/rack-protection" s.summary = s.description s.license = 'MIT' # generated from git shortlog -sn s.authors = [ "Konstantin Haase", "Alex Rodionov", "Patrick Ellis", "Jason Staten", "ITO Nobuaki", "Jeff Welling", "Matteo Centenaro", "Egor Homakov", "Florian Gilcher", "Fojas", "Igor Bochkariov", "Mael Clerambault", "Martin Mauch", "Renne Nissinen", "SAKAI, Kazuaki", "Stanislav Savulchik", "Steve Agalloco", "TOBY", "Thais Camilo and Konstantin Haase", "Vipul A M", "Akzhan Abdulin", "brookemckim", "Bj\u{f8}rge N\u{e6}ss", "Chris Heald", "Chris Mytton", "Corey Ward", "Dario Cravero", "David Kellum" ] # generated from git shortlog -sne s.email = [ "konstantin.mailinglists@googlemail.com", "p0deje@gmail.com", "jstaten07@gmail.com", "patrick@soundcloud.com", "jeff.welling@gmail.com", "bugant@gmail.com", "daydream.trippers@gmail.com", "florian.gilcher@asquera.de", "developer@fojasaur.us", "ujifgc@gmail.com", "mael@clerambault.fr", "martin.mauch@gmail.com", "rennex@iki.fi", "kaz.july.7@gmail.com", "s.savulchik@gmail.com", "steve.agalloco@gmail.com", "toby.net.info.mail+git@gmail.com", "dev+narwen+rkh@rkh.im", "vipulnsward@gmail.com", "akzhan.abdulin@gmail.com", "brooke@digitalocean.com", "bjoerge@bengler.no", "cheald@gmail.com", "self@hecticjeff.net", "coreyward@me.com", "dario@uxtemple.com", "dek-oss@gravitext.com", "homakov@gmail.com" ] # generated from git ls-files s.files = [ "License", "README.md", "Rakefile", "lib/rack-protection.rb", "lib/rack/protection.rb", "lib/rack/protection/authenticity_token.rb", "lib/rack/protection/base.rb", "lib/rack/protection/escaped_params.rb", "lib/rack/protection/form_token.rb", "lib/rack/protection/frame_options.rb", "lib/rack/protection/http_origin.rb", "lib/rack/protection/ip_spoofing.rb", "lib/rack/protection/json_csrf.rb", "lib/rack/protection/path_traversal.rb", "lib/rack/protection/remote_referrer.rb", "lib/rack/protection/remote_token.rb", "lib/rack/protection/session_hijacking.rb", "lib/rack/protection/version.rb", "lib/rack/protection/xss_header.rb", "rack-protection.gemspec", "spec/authenticity_token_spec.rb", "spec/base_spec.rb", "spec/escaped_params_spec.rb", "spec/form_token_spec.rb", "spec/frame_options_spec.rb", "spec/http_origin_spec.rb", "spec/ip_spoofing_spec.rb", "spec/json_csrf_spec.rb", "spec/path_traversal_spec.rb", "spec/protection_spec.rb", "spec/remote_referrer_spec.rb", "spec/remote_token_spec.rb", "spec/session_hijacking_spec.rb", "spec/spec_helper.rb", "spec/xss_header_spec.rb" ] # dependencies s.add_dependency "rack" s.add_development_dependency "rack-test" s.add_development_dependency "rspec", "~> 2.0" end rack-protection-1.5.3/lib/0000755000004100000410000000000012325252405015422 5ustar www-datawww-datarack-protection-1.5.3/lib/rack-protection.rb0000644000004100000410000000003212325252405021046 0ustar www-datawww-datarequire "rack/protection" rack-protection-1.5.3/lib/rack/0000755000004100000410000000000012325252405016342 5ustar www-datawww-datarack-protection-1.5.3/lib/rack/protection/0000755000004100000410000000000012325252405020530 5ustar www-datawww-datarack-protection-1.5.3/lib/rack/protection/xss_header.rb0000644000004100000410000000154412325252405023206 0ustar www-datawww-datarequire 'rack/protection' module Rack module Protection ## # Prevented attack:: Non-permanent XSS # Supported browsers:: Internet Explorer 8 and later # More infos:: http://blogs.msdn.com/b/ie/archive/2008/07/01/ie8-security-part-iv-the-xss-filter.aspx # # Sets X-XSS-Protection header to tell the browser to block attacks. # # Options: # xss_mode:: How the browser should prevent the attack (default: :block) class XSSHeader < Base default_options :xss_mode => :block, :nosniff => true def call(env) status, headers, body = @app.call(env) headers['X-XSS-Protection'] ||= "1; mode=#{options[:xss_mode]}" if html? headers headers['X-Content-Type-Options'] ||= 'nosniff' if options[:nosniff] [status, headers, body] end end end end rack-protection-1.5.3/lib/rack/protection/frame_options.rb0000644000004100000410000000234412325252405023725 0ustar www-datawww-datarequire 'rack/protection' module Rack module Protection ## # Prevented attack:: Clickjacking # Supported browsers:: Internet Explorer 8, Firefox 3.6.9, Opera 10.50, # Safari 4.0, Chrome 4.1.249.1042 and later # More infos:: https://developer.mozilla.org/en/The_X-FRAME-OPTIONS_response_header # # Sets X-Frame-Options header to tell the browser avoid embedding the page # in a frame. # # Options: # # frame_options:: Defines who should be allowed to embed the page in a # frame. Use :deny to forbid any embedding, :sameorigin # to allow embedding from the same origin (default). class FrameOptions < Base default_options :frame_options => :sameorigin def frame_options @frame_options ||= begin frame_options = options[:frame_options] frame_options = options[:frame_options].to_s.upcase unless frame_options.respond_to? :to_str frame_options.to_str end end def call(env) status, headers, body = @app.call(env) headers['X-Frame-Options'] ||= frame_options if html? headers [status, headers, body] end end end end rack-protection-1.5.3/lib/rack/protection/http_origin.rb0000644000004100000410000000203112325252405023377 0ustar www-datawww-datarequire '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_PORTS = { 'http' => 80, 'https' => 443, 'coffee' => 80 } default_reaction :deny def base_url(env) request = Rack::Request.new(env) port = ":#{request.port}" unless request.port == DEFAULT_PORTS[request.scheme] "#{request.scheme}://#{request.host}#{port}" end def accepts?(env) return true if safe? env return true unless origin = env['HTTP_ORIGIN'] return true if base_url(env) == origin Array(options[:origin_whitelist]).include? origin end end end end rack-protection-1.5.3/lib/rack/protection/remote_referrer.rb0000644000004100000410000000076212325252405024251 0ustar www-datawww-datarequire 'rack/protection' module Rack module Protection ## # Prevented attack:: CSRF # Supported browsers:: all # More infos:: http://en.wikipedia.org/wiki/Cross-site_request_forgery # # Does not accept unsafe HTTP requests if the Referer [sic] header is set to # a different host. class RemoteReferrer < Base default_reaction :deny def accepts?(env) safe?(env) or referrer(env) == Request.new(env).host end end end end rack-protection-1.5.3/lib/rack/protection/json_csrf.rb0000644000004100000410000000210112325252405023035 0ustar www-datawww-datarequire 'rack/protection' module Rack module Protection ## # Prevented attack:: CSRF # Supported browsers:: all # More infos:: http://flask.pocoo.org/docs/security/#json-security # # JSON GET APIs are vulnerable to being embedded as JavaScript while the # Array prototype has been patched to track data. Checks the referrer # even on GET requests if the content type is JSON. class JsonCsrf < Base alias react deny def call(env) request = Request.new(env) status, headers, body = app.call(env) if has_vector? request, headers warn env, "attack prevented by #{self.class}" react(env) or [status, headers, body] else [status, headers, body] end end def has_vector?(request, headers) return false if request.xhr? return false unless headers['Content-Type'].to_s.split(';', 2).first =~ /^\s*application\/json\s*$/ origin(request.env).nil? and referrer(request.env) != request.host end end end end rack-protection-1.5.3/lib/rack/protection/ip_spoofing.rb0000644000004100000410000000130112325252405023364 0ustar www-datawww-datarequire 'rack/protection' module Rack module Protection ## # Prevented attack:: IP spoofing # Supported browsers:: all # More infos:: http://blog.c22.cc/2011/04/22/surveymonkey-ip-spoofing/ # # Detect (some) IP spoofing attacks. class IPSpoofing < Base default_reaction :deny def accepts?(env) return true unless env.include? 'HTTP_X_FORWARDED_FOR' ips = env['HTTP_X_FORWARDED_FOR'].split(/\s*,\s*/) return false if env.include? 'HTTP_CLIENT_IP' and not ips.include? env['HTTP_CLIENT_IP'] return false if env.include? 'HTTP_X_REAL_IP' and not ips.include? env['HTTP_X_REAL_IP'] true end end end end rack-protection-1.5.3/lib/rack/protection/session_hijacking.rb0000644000004100000410000000226412325252405024553 0ustar www-datawww-datarequire 'rack/protection' module Rack module Protection ## # Prevented attack:: Session Hijacking # Supported browsers:: all # More infos:: http://en.wikipedia.org/wiki/Session_hijacking # # Tracks request properties like the user agent in the session and empties # the session if those properties change. This essentially prevents attacks # from Firesheep. Since all headers taken into consideration can be # spoofed, too, this will not prevent determined hijacking attempts. class SessionHijacking < Base default_reaction :drop_session default_options :tracking_key => :tracking, :encrypt_tracking => true, :track => %w[HTTP_USER_AGENT HTTP_ACCEPT_LANGUAGE] def accepts?(env) session = session env key = options[:tracking_key] if session.include? key session[key].all? { |k,v| v == encrypt(env[k]) } else session[key] = {} options[:track].each { |k| session[key][k] = encrypt(env[k]) } end end def encrypt(value) value = value.to_s.downcase options[:encrypt_tracking] ? super(value) : value end end end end rack-protection-1.5.3/lib/rack/protection/form_token.rb0000644000004100000410000000134112325252405023217 0ustar www-datawww-datarequire 'rack/protection' module Rack module Protection ## # Prevented attack:: CSRF # Supported browsers:: all # More infos:: http://en.wikipedia.org/wiki/Cross-site_request_forgery # # Only accepts submitted forms if a given access token matches the token # included in the session. Does not expect such a token from Ajax request. # # This middleware is not used when using the Rack::Protection collection, # since it might be a security issue, depending on your application # # Compatible with Rails and rack-csrf. class FormToken < AuthenticityToken def accepts?(env) env["HTTP_X_REQUESTED_WITH"] == "XMLHttpRequest" or super end end end end rack-protection-1.5.3/lib/rack/protection/version.rb0000644000004100000410000000050512325252405022542 0ustar www-datawww-datamodule Rack module Protection def self.version VERSION end SIGNATURE = [1, 5, 3] VERSION = SIGNATURE.join('.') VERSION.extend Comparable def VERSION.<=>(other) other = other.split('.').map { |i| i.to_i } if other.respond_to? :split SIGNATURE <=> Array(other) end end end rack-protection-1.5.3/lib/rack/protection/escaped_params.rb0000644000004100000410000000442212325252405024026 0ustar www-datawww-datarequire 'rack/protection' require 'rack/utils' begin require 'escape_utils' rescue LoadError end module Rack module Protection ## # Prevented attack:: XSS # Supported browsers:: all # More infos:: http://en.wikipedia.org/wiki/Cross-site_scripting # # Automatically escapes Rack::Request#params so they can be embedded in HTML # or JavaScript without any further issues. Calls +html_safe+ on the escaped # strings if defined, to avoid double-escaping in Rails. # # Options: # escape:: What escaping modes to use, should be Symbol or Array of Symbols. # Available: :html (default), :javascript, :url class EscapedParams < Base extend Rack::Utils class << self alias escape_url escape public :escape_html end default_options :escape => :html, :escaper => defined?(EscapeUtils) ? EscapeUtils : self def initialize(*) super modes = Array options[:escape] @escaper = options[:escaper] @html = modes.include? :html @javascript = modes.include? :javascript @url = modes.include? :url if @javascript and not @escaper.respond_to? :escape_javascript fail("Use EscapeUtils for JavaScript escaping.") end end def call(env) request = Request.new(env) get_was = handle(request.GET) post_was = handle(request.POST) rescue nil app.call env ensure request.GET.replace get_was if get_was request.POST.replace post_was if post_was end def handle(hash) was = hash.dup hash.replace escape(hash) was end def escape(object) case object when Hash then escape_hash(object) when Array then object.map { |o| escape(o) } when String then escape_string(object) else nil end end def escape_hash(hash) hash = hash.dup hash.each { |k,v| hash[k] = escape(v) } hash end def escape_string(str) str = @escaper.escape_url(str) if @url str = @escaper.escape_html(str) if @html str = @escaper.escape_javascript(str) if @javascript str end end end end rack-protection-1.5.3/lib/rack/protection/path_traversal.rb0000644000004100000410000000241312325252405024074 0ustar www-datawww-datarequire 'rack/protection' module Rack module Protection ## # Prevented attack:: Directory traversal # Supported browsers:: all # More infos:: http://en.wikipedia.org/wiki/Directory_traversal # # Unescapes '/' and '.', expands +path_info+. # Thus GET /foo/%2e%2e%2fbar becomes GET /bar. class PathTraversal < Base def call(env) path_was = env["PATH_INFO"] env["PATH_INFO"] = cleanup path_was if path_was && !path_was.empty? app.call env ensure env["PATH_INFO"] = path_was end def cleanup(path) if path.respond_to?(:encoding) # Ruby 1.9+ M17N encoding = path.encoding dot = '.'.encode(encoding) slash = '/'.encode(encoding) else # Ruby 1.8 dot = '.' slash = '/' end parts = [] unescaped = path.gsub(/%2e/i, dot).gsub(/%2f/i, slash) unescaped.split(slash).each do |part| next if part.empty? or part == dot part == '..' ? parts.pop : parts << part end cleaned = slash + parts.join(slash) cleaned << slash if parts.any? and unescaped =~ %r{/\.{0,2}$} cleaned end end end end rack-protection-1.5.3/lib/rack/protection/authenticity_token.rb0000644000004100000410000000161712325252405024774 0ustar www-datawww-datarequire 'rack/protection' module Rack module Protection ## # Prevented attack:: CSRF # Supported browsers:: all # More infos:: http://en.wikipedia.org/wiki/Cross-site_request_forgery # # Only accepts unsafe HTTP requests if a given access token matches the token # included in the session. # # Compatible with Rails and rack-csrf. # # Options: # # authenticity_param: Defines the param's name that should contain the token on a request. # class AuthenticityToken < Base default_options :authenticity_param => 'authenticity_token' def accepts?(env) session = session env token = session[:csrf] ||= session['_csrf_token'] || random_string safe?(env) || env['HTTP_X_CSRF_TOKEN'] == token || Request.new(env).params[options[:authenticity_param]] == token end end end end rack-protection-1.5.3/lib/rack/protection/base.rb0000755000004100000410000000634012325252405021775 0ustar www-datawww-datarequire 'rack/protection' require 'digest' require 'logger' require 'uri' module Rack module Protection class Base DEFAULT_OPTIONS = { :reaction => :default_reaction, :logging => true, :message => 'Forbidden', :encryptor => Digest::SHA1, :session_key => 'rack.session', :status => 403, :allow_empty_referrer => true, :report_key => "protection.failed", :html_types => %w[text/html application/xhtml] } attr_reader :app, :options def self.default_options(options) define_method(:default_options) { super().merge(options) } end def self.default_reaction(reaction) alias_method(:default_reaction, reaction) end def default_options DEFAULT_OPTIONS end def initialize(app, options = {}) @app, @options = app, default_options.merge(options) end def safe?(env) %w[GET HEAD OPTIONS TRACE].include? env['REQUEST_METHOD'] end def accepts?(env) raise NotImplementedError, "#{self.class} implementation pending" end def call(env) unless accepts? env instrument env result = react env end result or app.call(env) end def react(env) result = send(options[:reaction], env) result if Array === result and result.size == 3 end def warn(env, message) return unless options[:logging] l = options[:logger] || env['rack.logger'] || ::Logger.new(env['rack.errors']) l.warn(message) end def instrument(env) return unless i = options[:instrumenter] env['rack.protection.attack'] = self.class.name.split('::').last.downcase i.instrument('rack.protection', env) end def deny(env) warn env, "attack prevented by #{self.class}" [options[:status], {'Content-Type' => 'text/plain'}, [options[:message]]] end def report(env) warn env, "attack reported by #{self.class}" env[options[:report_key]] = true end def session?(env) env.include? options[:session_key] end def session(env) 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) ref = env['HTTP_REFERER'].to_s return if !options[:allow_empty_referrer] and ref.empty? URI.parse(ref).host || Request.new(env).host rescue URI::InvalidURIError end def origin(env) env['HTTP_ORIGIN'] || env['HTTP_X_ORIGIN'] end def random_string(secure = defined? SecureRandom) secure ? SecureRandom.hex(16) : "%032x" % rand(2**128-1) rescue NotImplementedError random_string false end def encrypt(value) options[:encryptor].hexdigest value.to_s end alias default_reaction deny def html?(headers) return false unless header = headers.detect { |k,v| k.downcase == 'content-type' } options[:html_types].include? header.last[/^\w+\/\w+/] end end end end rack-protection-1.5.3/lib/rack/protection/remote_token.rb0000644000004100000410000000113412325252405023547 0ustar www-datawww-datarequire 'rack/protection' module Rack module Protection ## # Prevented attack:: CSRF # Supported browsers:: all # More infos:: http://en.wikipedia.org/wiki/Cross-site_request_forgery # # Only accepts unsafe HTTP requests if a given access token matches the token # included in the session *or* the request comes from the same origin. # # Compatible with Rails and rack-csrf. class RemoteToken < AuthenticityToken default_reaction :deny def accepts?(env) super or referrer(env) == Request.new(env).host end end end end rack-protection-1.5.3/lib/rack/protection.rb0000644000004100000410000000426712325252405021066 0ustar www-datawww-datarequire 'rack/protection/version' require 'rack' module Rack module Protection autoload :AuthenticityToken, 'rack/protection/authenticity_token' autoload :Base, 'rack/protection/base' 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' autoload :RemoteReferrer, 'rack/protection/remote_referrer' autoload :RemoteToken, 'rack/protection/remote_token' autoload :SessionHijacking, 'rack/protection/session_hijacking' autoload :XSSHeader, 'rack/protection/xss_header' def self.new(app, options = {}) # does not include: RemoteReferrer, AuthenticityToken and FormToken except = Array options[:except] use_these = Array options[:use] Rack::Builder.new do use ::Rack::Protection::RemoteReferrer, options if use_these.include? :remote_referrer use ::Rack::Protection::AuthenticityToken,options if use_these.include? :authenticity_token use ::Rack::Protection::FormToken, options if use_these.include? :form_token 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 use ::Rack::Protection::RemoteToken, options unless except.include? :remote_token use ::Rack::Protection::SessionHijacking, options unless except.include? :session_hijacking use ::Rack::Protection::XSSHeader, options unless except.include? :xss_header run app end.to_app end end end rack-protection-1.5.3/metadata.yml0000644000004100000410000001007112325252405017156 0ustar www-datawww-data--- !ruby/object:Gem::Specification name: rack-protection version: !ruby/object:Gem::Version version: 1.5.3 platform: ruby authors: - Konstantin Haase - Alex Rodionov - Patrick Ellis - Jason Staten - ITO Nobuaki - Jeff Welling - Matteo Centenaro - Egor Homakov - Florian Gilcher - Fojas - Igor Bochkariov - Mael Clerambault - Martin Mauch - Renne Nissinen - SAKAI, Kazuaki - Stanislav Savulchik - Steve Agalloco - TOBY - Thais Camilo and Konstantin Haase - Vipul A M - Akzhan Abdulin - brookemckim - Bjørge Næss - Chris Heald - Chris Mytton - Corey Ward - Dario Cravero - David Kellum autorequire: bindir: bin cert_chain: [] date: 2014-04-08 00:00:00.000000000 Z dependencies: - !ruby/object:Gem::Dependency name: rack requirement: !ruby/object:Gem::Requirement requirements: - - ">=" - !ruby/object:Gem::Version version: '0' type: :runtime prerelease: false version_requirements: !ruby/object:Gem::Requirement requirements: - - ">=" - !ruby/object:Gem::Version version: '0' - !ruby/object:Gem::Dependency name: rack-test requirement: !ruby/object:Gem::Requirement requirements: - - ">=" - !ruby/object:Gem::Version version: '0' type: :development prerelease: false version_requirements: !ruby/object:Gem::Requirement requirements: - - ">=" - !ruby/object:Gem::Version version: '0' - !ruby/object:Gem::Dependency name: rspec requirement: !ruby/object:Gem::Requirement requirements: - - "~>" - !ruby/object:Gem::Version version: '2.0' type: :development prerelease: false version_requirements: !ruby/object:Gem::Requirement requirements: - - "~>" - !ruby/object:Gem::Version version: '2.0' description: You should use protection! email: - konstantin.mailinglists@googlemail.com - p0deje@gmail.com - jstaten07@gmail.com - patrick@soundcloud.com - jeff.welling@gmail.com - bugant@gmail.com - daydream.trippers@gmail.com - florian.gilcher@asquera.de - developer@fojasaur.us - ujifgc@gmail.com - mael@clerambault.fr - martin.mauch@gmail.com - rennex@iki.fi - kaz.july.7@gmail.com - s.savulchik@gmail.com - steve.agalloco@gmail.com - toby.net.info.mail+git@gmail.com - dev+narwen+rkh@rkh.im - vipulnsward@gmail.com - akzhan.abdulin@gmail.com - brooke@digitalocean.com - bjoerge@bengler.no - cheald@gmail.com - self@hecticjeff.net - coreyward@me.com - dario@uxtemple.com - dek-oss@gravitext.com - homakov@gmail.com executables: [] extensions: [] extra_rdoc_files: [] files: - License - README.md - Rakefile - lib/rack-protection.rb - lib/rack/protection.rb - lib/rack/protection/authenticity_token.rb - lib/rack/protection/base.rb - lib/rack/protection/escaped_params.rb - lib/rack/protection/form_token.rb - lib/rack/protection/frame_options.rb - lib/rack/protection/http_origin.rb - lib/rack/protection/ip_spoofing.rb - lib/rack/protection/json_csrf.rb - lib/rack/protection/path_traversal.rb - lib/rack/protection/remote_referrer.rb - lib/rack/protection/remote_token.rb - lib/rack/protection/session_hijacking.rb - lib/rack/protection/version.rb - lib/rack/protection/xss_header.rb - rack-protection.gemspec - spec/authenticity_token_spec.rb - spec/base_spec.rb - spec/escaped_params_spec.rb - spec/form_token_spec.rb - spec/frame_options_spec.rb - spec/http_origin_spec.rb - spec/ip_spoofing_spec.rb - spec/json_csrf_spec.rb - spec/path_traversal_spec.rb - spec/protection_spec.rb - spec/remote_referrer_spec.rb - spec/remote_token_spec.rb - spec/session_hijacking_spec.rb - spec/spec_helper.rb - spec/xss_header_spec.rb homepage: http://github.com/rkh/rack-protection licenses: - MIT metadata: {} post_install_message: rdoc_options: [] require_paths: - lib required_ruby_version: !ruby/object:Gem::Requirement requirements: - - ">=" - !ruby/object:Gem::Version version: '0' required_rubygems_version: !ruby/object:Gem::Requirement requirements: - - ">=" - !ruby/object:Gem::Version version: '0' requirements: [] rubyforge_project: rubygems_version: 2.0.14 signing_key: specification_version: 4 summary: You should use protection! test_files: [] has_rdoc: rack-protection-1.5.3/checksums.yaml.gz0000444000004100000410000000041412325252405020141 0ustar www-datawww-dataZDSe=R@F"B:;{OZ8ܓyד _RڼSd ; :path_traversal run MyApp ``` Use a single protection middleware: ``` ruby # config.ru require 'rack/protection' use Rack::Protection::AuthenticityToken run MyApp ``` # Prevented Attacks ## Cross Site Request Forgery Prevented by: * `Rack::Protection::AuthenticityToken` (not included by `use Rack::Protection`) * `Rack::Protection::FormToken` (not included by `use Rack::Protection`) * `Rack::Protection::JsonCsrf` * `Rack::Protection::RemoteReferrer` (not included by `use Rack::Protection`) * `Rack::Protection::RemoteToken` * `Rack::Protection::HttpOrigin` ## Cross Site Scripting Prevented by: * `Rack::Protection::EscapedParams` (not included by `use Rack::Protection`) * `Rack::Protection::XSSHeader` (Internet Explorer only) ## Clickjacking Prevented by: * `Rack::Protection::FrameOptions` ## Directory Traversal Prevented by: * `Rack::Protection::PathTraversal` ## Session Hijacking Prevented by: * `Rack::Protection::SessionHijacking` ## IP Spoofing Prevented by: * `Rack::Protection::IPSpoofing` # Installation gem install rack-protection # Instrumentation Instrumentation is enabled by passing in an instrumenter as an option. ``` use Rack::Protection, instrumenter: ActiveSupport::Notifications ``` The instrumenter is passed a namespace (String) and environment (Hash). The namespace is 'rack.protection' and the attack type can be obtained from the environment key 'rack.protection.attack'.