rack-protection 1.5.3 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

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