rack-protection 1.5.3 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of rack-protection might be problematic. Click here for more details.

@@ -1,48 +0,0 @@
1
- require File.expand_path('../spec_helper.rb', __FILE__)
2
-
3
- describe Rack::Protection::AuthenticityToken do
4
- it_behaves_like "any rack application"
5
-
6
- it "denies post requests without any token" do
7
- post('/').should_not be_ok
8
- end
9
-
10
- it "accepts post requests with correct X-CSRF-Token header" do
11
- post('/', {}, 'rack.session' => {:csrf => "a"}, 'HTTP_X_CSRF_TOKEN' => "a")
12
- last_response.should be_ok
13
- end
14
-
15
- it "denies post requests with wrong X-CSRF-Token header" do
16
- post('/', {}, 'rack.session' => {:csrf => "a"}, 'HTTP_X_CSRF_TOKEN' => "b")
17
- last_response.should_not be_ok
18
- end
19
-
20
- it "accepts post form requests with correct authenticity_token field" do
21
- post('/', {"authenticity_token" => "a"}, 'rack.session' => {:csrf => "a"})
22
- last_response.should be_ok
23
- end
24
-
25
- it "denies post form requests with wrong authenticity_token field" do
26
- post('/', {"authenticity_token" => "a"}, 'rack.session' => {:csrf => "b"})
27
- last_response.should_not be_ok
28
- end
29
-
30
- it "prevents ajax requests without a valid token" do
31
- post('/', {}, "HTTP_X_REQUESTED_WITH" => "XMLHttpRequest").should_not be_ok
32
- end
33
-
34
- it "allows for a custom authenticity token param" do
35
- mock_app do
36
- use Rack::Protection::AuthenticityToken, :authenticity_param => 'csrf_param'
37
- run proc { |e| [200, {'Content-Type' => 'text/plain'}, ['hi']] }
38
- end
39
-
40
- post('/', {"csrf_param" => "a"}, 'rack.session' => {:csrf => "a"})
41
- last_response.should be_ok
42
- end
43
-
44
- it "sets a new csrf token for the session in env, even after a 'safe' request" do
45
- get('/', {}, {})
46
- env['rack.session'][:csrf].should_not be_nil
47
- end
48
- end
data/spec/base_spec.rb DELETED
@@ -1,40 +0,0 @@
1
- require File.expand_path('../spec_helper.rb', __FILE__)
2
-
3
- describe Rack::Protection::Base do
4
-
5
- subject { described_class.new(lambda {}) }
6
-
7
- describe "#random_string" do
8
- it "outputs a string of 32 characters" do
9
- subject.random_string.length.should == 32
10
- end
11
- end
12
-
13
- describe "#referrer" do
14
- it "Reads referrer from Referer header" do
15
- env = {"HTTP_HOST" => "foo.com", "HTTP_REFERER" => "http://bar.com/valid"}
16
- subject.referrer(env).should == "bar.com"
17
- end
18
-
19
- it "Reads referrer from Host header when Referer header is relative" do
20
- env = {"HTTP_HOST" => "foo.com", "HTTP_REFERER" => "/valid"}
21
- subject.referrer(env).should == "foo.com"
22
- end
23
-
24
- it "Reads referrer from Host header when Referer header is missing" do
25
- env = {"HTTP_HOST" => "foo.com"}
26
- subject.referrer(env).should == "foo.com"
27
- end
28
-
29
- it "Returns nil when Referer header is missing and allow_empty_referrer is false" do
30
- env = {"HTTP_HOST" => "foo.com"}
31
- subject.options[:allow_empty_referrer] = false
32
- subject.referrer(env).should be_nil
33
- end
34
-
35
- it "Returns nil when Referer header is invalid" do
36
- env = {"HTTP_HOST" => "foo.com", "HTTP_REFERER" => "http://bar.com/bad|uri"}
37
- subject.referrer(env).should be_nil
38
- end
39
- end
40
- end
@@ -1,43 +0,0 @@
1
- require File.expand_path('../spec_helper.rb', __FILE__)
2
-
3
- describe Rack::Protection::EscapedParams do
4
- it_behaves_like "any rack application"
5
-
6
- context 'escaping' do
7
- it 'escapes html entities' do
8
- mock_app do |env|
9
- request = Rack::Request.new(env)
10
- [200, {'Content-Type' => 'text/plain'}, [request.params['foo']]]
11
- end
12
- get '/', :foo => "<bar>"
13
- body.should == '&lt;bar&gt;'
14
- end
15
-
16
- it 'leaves normal params untouched' do
17
- mock_app do |env|
18
- request = Rack::Request.new(env)
19
- [200, {'Content-Type' => 'text/plain'}, [request.params['foo']]]
20
- end
21
- get '/', :foo => "bar"
22
- body.should == 'bar'
23
- end
24
-
25
- it 'copes with nested arrays' do
26
- mock_app do |env|
27
- request = Rack::Request.new(env)
28
- [200, {'Content-Type' => 'text/plain'}, [request.params['foo']['bar']]]
29
- end
30
- get '/', :foo => {:bar => "<bar>"}
31
- body.should == '&lt;bar&gt;'
32
- end
33
-
34
- it 'leaves cache-breaker params untouched' do
35
- mock_app do |env|
36
- [200, {'Content-Type' => 'text/plain'}, ['hi']]
37
- end
38
-
39
- get '/?95df8d9bf5237ad08df3115ee74dcb10'
40
- body.should == 'hi'
41
- end
42
- end
43
- end
@@ -1,33 +0,0 @@
1
- require File.expand_path('../spec_helper.rb', __FILE__)
2
-
3
- describe Rack::Protection::FormToken do
4
- it_behaves_like "any rack application"
5
-
6
- it "denies post requests without any token" do
7
- post('/').should_not be_ok
8
- end
9
-
10
- it "accepts post requests with correct X-CSRF-Token header" do
11
- post('/', {}, 'rack.session' => {:csrf => "a"}, 'HTTP_X_CSRF_TOKEN' => "a")
12
- last_response.should be_ok
13
- end
14
-
15
- it "denies post requests with wrong X-CSRF-Token header" do
16
- post('/', {}, 'rack.session' => {:csrf => "a"}, 'HTTP_X_CSRF_TOKEN' => "b")
17
- last_response.should_not be_ok
18
- end
19
-
20
- it "accepts post form requests with correct authenticity_token field" do
21
- post('/', {"authenticity_token" => "a"}, 'rack.session' => {:csrf => "a"})
22
- last_response.should be_ok
23
- end
24
-
25
- it "denies post form requests with wrong authenticity_token field" do
26
- post('/', {"authenticity_token" => "a"}, 'rack.session' => {:csrf => "b"})
27
- last_response.should_not be_ok
28
- end
29
-
30
- it "accepts ajax requests without a valid token" do
31
- post('/', {}, "HTTP_X_REQUESTED_WITH" => "XMLHttpRequest").should be_ok
32
- end
33
- end
@@ -1,39 +0,0 @@
1
- require File.expand_path('../spec_helper.rb', __FILE__)
2
-
3
- describe Rack::Protection::FrameOptions do
4
- it_behaves_like "any rack application"
5
-
6
- it 'should set the X-Frame-Options' do
7
- get('/', {}, 'wants' => 'text/html').headers["X-Frame-Options"].should == "SAMEORIGIN"
8
- end
9
-
10
- it 'should not set the X-Frame-Options for other content types' do
11
- get('/', {}, 'wants' => 'text/foo').headers["X-Frame-Options"].should be_nil
12
- end
13
-
14
- it 'should allow changing the protection mode' do
15
- # I have no clue what other modes are available
16
- mock_app do
17
- use Rack::Protection::FrameOptions, :frame_options => :deny
18
- run DummyApp
19
- end
20
-
21
- get('/', {}, 'wants' => 'text/html').headers["X-Frame-Options"].should == "DENY"
22
- end
23
-
24
-
25
- it 'should allow changing the protection mode to a string' do
26
- # I have no clue what other modes are available
27
- mock_app do
28
- use Rack::Protection::FrameOptions, :frame_options => "ALLOW-FROM foo"
29
- run DummyApp
30
- end
31
-
32
- get('/', {}, 'wants' => 'text/html').headers["X-Frame-Options"].should == "ALLOW-FROM foo"
33
- end
34
-
35
- it 'should not override the header if already set' do
36
- mock_app with_headers("X-Frame-Options" => "allow")
37
- get('/', {}, 'wants' => 'text/html').headers["X-Frame-Options"].should == "allow"
38
- end
39
- end
@@ -1,38 +0,0 @@
1
- require File.expand_path('../spec_helper.rb', __FILE__)
2
-
3
- describe Rack::Protection::HttpOrigin do
4
- it_behaves_like "any rack application"
5
-
6
- before(:each) do
7
- mock_app do
8
- use Rack::Protection::HttpOrigin
9
- run DummyApp
10
- end
11
- end
12
-
13
- %w(GET HEAD POST PUT DELETE).each do |method|
14
- it "accepts #{method} requests with no Origin" do
15
- send(method.downcase, '/').should be_ok
16
- end
17
- end
18
-
19
- %w(GET HEAD).each do |method|
20
- it "accepts #{method} requests with non-whitelisted Origin" do
21
- send(method.downcase, '/', {}, 'HTTP_ORIGIN' => 'http://malicious.com').should be_ok
22
- end
23
- end
24
-
25
- %w(POST PUT DELETE).each do |method|
26
- it "denies #{method} requests with non-whitelisted Origin" do
27
- send(method.downcase, '/', {}, 'HTTP_ORIGIN' => 'http://malicious.com').should_not be_ok
28
- end
29
-
30
- it "accepts #{method} requests with whitelisted Origin" do
31
- mock_app do
32
- use Rack::Protection::HttpOrigin, :origin_whitelist => ['http://www.friend.com']
33
- run DummyApp
34
- end
35
- send(method.downcase, '/', {}, 'HTTP_ORIGIN' => 'http://www.friend.com').should be_ok
36
- end
37
- end
38
- end
@@ -1,35 +0,0 @@
1
- require File.expand_path('../spec_helper.rb', __FILE__)
2
-
3
- describe Rack::Protection::IPSpoofing do
4
- it_behaves_like "any rack application"
5
-
6
- it 'accepts requests without X-Forward-For header' do
7
- get('/', {}, 'HTTP_CLIENT_IP' => '1.2.3.4', 'HTTP_X_REAL_IP' => '4.3.2.1')
8
- last_response.should be_ok
9
- end
10
-
11
- it 'accepts requests with proper X-Forward-For header' do
12
- get('/', {}, 'HTTP_CLIENT_IP' => '1.2.3.4',
13
- 'HTTP_X_FORWARDED_FOR' => '192.168.1.20, 1.2.3.4, 127.0.0.1')
14
- last_response.should be_ok
15
- end
16
-
17
- it 'denies requests where the client spoofs X-Forward-For but not the IP' do
18
- get('/', {}, 'HTTP_CLIENT_IP' => '1.2.3.4', 'HTTP_X_FORWARDED_FOR' => '1.2.3.5')
19
- last_response.should_not be_ok
20
- end
21
-
22
- it 'denies requests where the client spoofs the IP but not X-Forward-For' do
23
- get('/', {}, 'HTTP_CLIENT_IP' => '1.2.3.5',
24
- 'HTTP_X_FORWARDED_FOR' => '192.168.1.20, 1.2.3.4, 127.0.0.1')
25
- last_response.should_not be_ok
26
- end
27
-
28
- it 'denies requests where IP and X-Forward-For are spoofed but not X-Real-IP' do
29
- get('/', {},
30
- 'HTTP_CLIENT_IP' => '1.2.3.5',
31
- 'HTTP_X_FORWARDED_FOR' => '1.2.3.5',
32
- 'HTTP_X_REAL_IP' => '1.2.3.4')
33
- last_response.should_not be_ok
34
- end
35
- end
@@ -1,58 +0,0 @@
1
- require File.expand_path('../spec_helper.rb', __FILE__)
2
-
3
- describe Rack::Protection::JsonCsrf do
4
- it_behaves_like "any rack application"
5
-
6
- describe 'json response' do
7
- before do
8
- mock_app { |e| [200, {'Content-Type' => 'application/json'}, []]}
9
- end
10
-
11
- it "denies get requests with json responses with a remote referrer" do
12
- get('/', {}, 'HTTP_REFERER' => 'http://evil.com').should_not be_ok
13
- end
14
-
15
- it "accepts requests with json responses with a remote referrer when there's an origin header set" do
16
- get('/', {}, 'HTTP_REFERER' => 'http://good.com', 'HTTP_ORIGIN' => 'http://good.com').should be_ok
17
- end
18
-
19
- it "accepts requests with json responses with a remote referrer when there's an x-origin header set" do
20
- get('/', {}, 'HTTP_REFERER' => 'http://good.com', 'HTTP_X_ORIGIN' => 'http://good.com').should be_ok
21
- end
22
-
23
- it "accepts get requests with json responses with a local referrer" do
24
- get('/', {}, 'HTTP_REFERER' => '/').should be_ok
25
- end
26
-
27
- it "accepts get requests with json responses with no referrer" do
28
- get('/', {}).should be_ok
29
- end
30
-
31
- it "accepts XHR requests" do
32
- get('/', {}, 'HTTP_REFERER' => 'http://evil.com', 'HTTP_X_REQUESTED_WITH' => 'XMLHttpRequest').should be_ok
33
- end
34
-
35
- end
36
-
37
- describe 'not json response' do
38
-
39
- it "accepts get requests with 304 headers" do
40
- mock_app { |e| [304, {}, []]}
41
- get('/', {}).status.should == 304
42
- end
43
-
44
- end
45
-
46
- describe 'with drop_session as default reaction' do
47
- it 'still denies' do
48
- mock_app do
49
- use Rack::Protection, :reaction => :drop_session
50
- run proc { |e| [200, {'Content-Type' => 'application/json'}, []]}
51
- end
52
-
53
- session = {:foo => :bar}
54
- get('/', {}, 'HTTP_REFERER' => 'http://evil.com', 'rack.session' => session)
55
- last_response.should_not be_ok
56
- end
57
- end
58
- end
@@ -1,41 +0,0 @@
1
- require File.expand_path('../spec_helper.rb', __FILE__)
2
-
3
- describe Rack::Protection::PathTraversal do
4
- it_behaves_like "any rack application"
5
-
6
- context 'escaping' do
7
- before do
8
- mock_app { |e| [200, {'Content-Type' => 'text/plain'}, [e['PATH_INFO']]] }
9
- end
10
-
11
- %w[/foo/bar /foo/bar/ / /.f /a.x].each do |path|
12
- it("does not touch #{path.inspect}") { get(path).body.should == path }
13
- end
14
-
15
- { # yes, this is ugly, feel free to change that
16
- '/..' => '/', '/a/../b' => '/b', '/a/../b/' => '/b/', '/a/.' => '/a/',
17
- '/%2e.' => '/', '/a/%2E%2e/b' => '/b', '/a%2f%2E%2e%2Fb/' => '/b/',
18
- '//' => '/', '/%2fetc%2Fpasswd' => '/etc/passwd'
19
- }.each do |a, b|
20
- it("replaces #{a.inspect} with #{b.inspect}") { get(a).body.should == b }
21
- end
22
-
23
- it 'should be able to deal with PATH_INFO = nil (fcgi?)' do
24
- app = Rack::Protection::PathTraversal.new(proc { 42 })
25
- app.call({}).should be == 42
26
- end
27
- end
28
-
29
- if "".respond_to?(:encoding) # Ruby 1.9+ M17N
30
- context "PATH_INFO's encoding" do
31
- before do
32
- @app = Rack::Protection::PathTraversal.new(proc { |e| [200, {'Content-Type' => 'text/plain'}, [e['PATH_INFO'].encoding.to_s]] })
33
- end
34
-
35
- it 'should remain unchanged as ASCII-8BIT' do
36
- body = @app.call({ 'PATH_INFO' => '/'.encode('ASCII-8BIT') })[2][0]
37
- body.should == 'ASCII-8BIT'
38
- end
39
- end
40
- end
41
- end
@@ -1,105 +0,0 @@
1
- require File.expand_path('../spec_helper.rb', __FILE__)
2
-
3
- describe Rack::Protection do
4
- it_behaves_like "any rack application"
5
-
6
- it 'passes on options' do
7
- mock_app do
8
- use Rack::Protection, :track => ['HTTP_FOO']
9
- run proc { |e| [200, {'Content-Type' => 'text/plain'}, ['hi']] }
10
- end
11
-
12
- session = {:foo => :bar}
13
- get '/', {}, 'rack.session' => session, 'HTTP_ACCEPT_ENCODING' => 'a'
14
- get '/', {}, 'rack.session' => session, 'HTTP_ACCEPT_ENCODING' => 'b'
15
- session[:foo].should be == :bar
16
-
17
- get '/', {}, 'rack.session' => session, 'HTTP_FOO' => 'BAR'
18
- session.should be_empty
19
- end
20
-
21
- it 'passes errors through if :reaction => :report is used' do
22
- mock_app do
23
- use Rack::Protection, :reaction => :report
24
- run proc { |e| [200, {'Content-Type' => 'text/plain'}, [e["protection.failed"].to_s]] }
25
- end
26
-
27
- session = {:foo => :bar}
28
- post('/', {}, 'rack.session' => session, 'HTTP_ORIGIN' => 'http://malicious.com')
29
- last_response.should be_ok
30
- body.should == "true"
31
- end
32
-
33
- describe "#react" do
34
- it 'prevents attacks and warns about it' do
35
- io = StringIO.new
36
- mock_app do
37
- use Rack::Protection, :logger => Logger.new(io)
38
- run DummyApp
39
- end
40
- post('/', {}, 'rack.session' => {}, 'HTTP_ORIGIN' => 'http://malicious.com')
41
- io.string.should match /prevented.*Origin/
42
- end
43
-
44
- it 'reports attacks if reaction is to report' do
45
- io = StringIO.new
46
- mock_app do
47
- use Rack::Protection, :reaction => :report, :logger => Logger.new(io)
48
- run DummyApp
49
- end
50
- post('/', {}, 'rack.session' => {}, 'HTTP_ORIGIN' => 'http://malicious.com')
51
- io.string.should match /reported.*Origin/
52
- io.string.should_not match /prevented.*Origin/
53
- end
54
-
55
- it 'passes errors to reaction method if specified' do
56
- io = StringIO.new
57
- Rack::Protection::Base.send(:define_method, :special) { |*args| io << args.inspect }
58
- mock_app do
59
- use Rack::Protection, :reaction => :special, :logger => Logger.new(io)
60
- run DummyApp
61
- end
62
- post('/', {}, 'rack.session' => {}, 'HTTP_ORIGIN' => 'http://malicious.com')
63
- io.string.should match /HTTP_ORIGIN.*malicious.com/
64
- io.string.should_not match /reported|prevented/
65
- end
66
- end
67
-
68
- describe "#html?" do
69
- context "given an appropriate content-type header" do
70
- subject { Rack::Protection::Base.new(nil).html? 'content-type' => "text/html" }
71
- it { should be_true }
72
- end
73
-
74
- context "given an inappropriate content-type header" do
75
- subject { Rack::Protection::Base.new(nil).html? 'content-type' => "image/gif" }
76
- it { should be_false }
77
- end
78
-
79
- context "given no content-type header" do
80
- subject { Rack::Protection::Base.new(nil).html?({}) }
81
- it { should be_false }
82
- end
83
- end
84
-
85
- describe "#instrument" do
86
- let(:env) { { 'rack.protection.attack' => 'base' } }
87
- let(:instrumenter) { double('Instrumenter') }
88
-
89
- after do
90
- app.instrument(env)
91
- end
92
-
93
- context 'with an instrumenter specified' do
94
- let(:app) { Rack::Protection::Base.new(nil, :instrumenter => instrumenter) }
95
-
96
- it { instrumenter.should_receive(:instrument).with('rack.protection', env) }
97
- end
98
-
99
- context 'with no instrumenter specified' do
100
- let(:app) { Rack::Protection::Base.new(nil) }
101
-
102
- it { instrumenter.should_not_receive(:instrument) }
103
- end
104
- end
105
- end