rack-protection 1.5.0 → 1.5.1

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.

@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: d142ba2e517a486c07d79a7c7a80061fe405a84d
4
+ data.tar.gz: 43a1d8c17e3bc26171c5c75bc22eaded63b4587c
5
+ SHA512:
6
+ metadata.gz: df0552ef6da37611e34ff91e664521794681596cfd3898bf1cd5acb8150eea553db1bc761dc9fc3c90900884a3f5128368096bd9a1e386c84e90fe9c0fb83431
7
+ data.tar.gz: 4903af66fc37585786fb5650f9475695d3f0455f984c2621bc35ed9ae7addb19588fbc55d134cbf891f972c0316305e426c0d90ecdd9431273ad69a37585ef92
data/README.md CHANGED
@@ -80,3 +80,11 @@ Prevented by:
80
80
 
81
81
  gem install rack-protection
82
82
 
83
+ # Instrumentation
84
+
85
+ Instrumentation is enabled by passing in an instrumenter as an option.
86
+ ```
87
+ use Rack::Protection, instrumenter: ActiveSupport::Notifications
88
+ ```
89
+
90
+ 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'.
@@ -11,13 +11,20 @@ module Rack
11
11
  # included in the session.
12
12
  #
13
13
  # Compatible with Rails and rack-csrf.
14
+ #
15
+ # Options:
16
+ #
17
+ # authenticity_param: Defines the param's name that should contain the token on a request.
18
+ #
14
19
  class AuthenticityToken < Base
20
+ default_options :authenticity_param => 'authenticity_token'
21
+
15
22
  def accepts?(env)
16
- return true if safe? env
17
23
  session = session env
18
24
  token = session[:csrf] ||= session['_csrf_token'] || random_string
19
- env['HTTP_X_CSRF_TOKEN'] == token or
20
- Request.new(env).params['authenticity_token'] == token
25
+ safe?(env) ||
26
+ env['HTTP_X_CSRF_TOKEN'] == token ||
27
+ Request.new(env).params[options[:authenticity_param]] == token
21
28
  end
22
29
  end
23
30
  end
@@ -44,6 +44,7 @@ module Rack
44
44
  def call(env)
45
45
  unless accepts? env
46
46
  warn env, "attack prevented by #{self.class}"
47
+ instrument env
47
48
  result = react env
48
49
  end
49
50
  result or app.call(env)
@@ -60,6 +61,12 @@ module Rack
60
61
  l.warn(message)
61
62
  end
62
63
 
64
+ def instrument(env)
65
+ return unless i = options[:instrumenter]
66
+ env['rack.protection.attack'] = self.class.name.split('::').last.downcase
67
+ i.instrument('rack.protection', env)
68
+ end
69
+
63
70
  def deny(env)
64
71
  [options[:status], {'Content-Type' => 'text/plain'}, [options[:message]]]
65
72
  end
@@ -92,7 +99,7 @@ module Rack
92
99
  end
93
100
 
94
101
  def random_string(secure = defined? SecureRandom)
95
- secure ? SecureRandom.hex(32) : "%032x" % rand(2**128-1)
102
+ secure ? SecureRandom.hex(16) : "%032x" % rand(2**128-1)
96
103
  rescue NotImplementedError
97
104
  random_string false
98
105
  end
@@ -11,7 +11,7 @@ module Rack
11
11
  # Array prototype has been patched to track data. Checks the referrer
12
12
  # even on GET requests if the content type is JSON.
13
13
  class JsonCsrf < Base
14
- default_reaction :deny
14
+ alias react deny
15
15
 
16
16
  def call(env)
17
17
  request = Request.new(env)
@@ -19,7 +19,7 @@ module Rack
19
19
 
20
20
  if has_vector? request, headers
21
21
  warn env, "attack prevented by #{self.class}"
22
- react(env)
22
+ react(env) or [status, headers, body]
23
23
  else
24
24
  [status, headers, body]
25
25
  end
@@ -19,16 +19,27 @@ module Rack
19
19
  end
20
20
 
21
21
  def cleanup(path)
22
+ if path.respond_to?(:encoding)
23
+ # Ruby 1.9+ M17N
24
+ encoding = path.encoding
25
+ dot = '.'.encode(encoding)
26
+ slash = '/'.encode(encoding)
27
+ else
28
+ # Ruby 1.8
29
+ dot = '.'
30
+ slash = '/'
31
+ end
32
+
22
33
  parts = []
23
- unescaped = path.gsub('%2e', '.').gsub('%2f', '/')
34
+ unescaped = path.gsub(/%2e/i, dot).gsub(/%2f/i, slash)
24
35
 
25
- unescaped.split('/').each do |part|
26
- next if part.empty? or part == '.'
36
+ unescaped.split(slash).each do |part|
37
+ next if part.empty? or part == dot
27
38
  part == '..' ? parts.pop : parts << part
28
39
  end
29
40
 
30
- cleaned = '/' << parts.join('/')
31
- cleaned << '/' if parts.any? and unescaped =~ /\/\.{0,2}$/
41
+ cleaned = slash + parts.join(slash)
42
+ cleaned << slash if parts.any? and unescaped =~ %r{/\.{0,2}$}
32
43
  cleaned
33
44
  end
34
45
  end
@@ -4,7 +4,7 @@ module Rack
4
4
  VERSION
5
5
  end
6
6
 
7
- SIGNATURE = [1, 5, 0]
7
+ SIGNATURE = [1, 5, 1]
8
8
  VERSION = SIGNATURE.join('.')
9
9
 
10
10
  VERSION.extend Comparable
@@ -2,18 +2,20 @@
2
2
  Gem::Specification.new do |s|
3
3
  # general infos
4
4
  s.name = "rack-protection"
5
- s.version = "1.5.0"
5
+ s.version = "1.5.1"
6
6
  s.description = "You should use protection!"
7
7
  s.homepage = "http://github.com/rkh/rack-protection"
8
8
  s.summary = s.description
9
+ s.license = 'MIT'
9
10
 
10
11
  # generated from git shortlog -sn
11
12
  s.authors = [
12
13
  "Konstantin Haase",
13
14
  "Alex Rodionov",
14
- "Chris Heald",
15
- "Chris Mytton",
16
- "Corey Ward",
15
+ "Patrick Ellis",
16
+ "Jeff Welling",
17
+ "ITO Nobuaki",
18
+ "Matteo Centenaro",
17
19
  "David Kellum",
18
20
  "Egor Homakov",
19
21
  "Florian Gilcher",
@@ -23,18 +25,24 @@ Gem::Specification.new do |s|
23
25
  "SAKAI, Kazuaki",
24
26
  "Stanislav Savulchik",
25
27
  "Steve Agalloco",
26
- "Akzhan Abdulin",
27
28
  "TOBY",
28
- "Bj\u00F8rge N\u00E6ss"
29
+ "Akzhan Abdulin",
30
+ "brookemckim",
31
+ "Bj\u00F8rge N\u00E6ss",
32
+ "Chris Heald",
33
+ "Chris Mytton",
34
+ "Corey Ward",
35
+ "Dario Cravero"
29
36
  ]
30
37
 
31
38
  # generated from git shortlog -sne
32
39
  s.email = [
33
40
  "konstantin.mailinglists@googlemail.com",
34
41
  "p0deje@gmail.com",
35
- "self@hecticjeff.net",
36
- "coreyward@me.com",
37
- "dek-oss@gravitext.com",
42
+ "patrick@soundcloud.com",
43
+ "jeff.welling@gmail.com",
44
+ "bugant@gmail.com",
45
+ "daydream.trippers@gmail.com",
38
46
  "homakov@gmail.com",
39
47
  "florian.gilcher@asquera.de",
40
48
  "developer@fojasaur.us",
@@ -43,10 +51,15 @@ Gem::Specification.new do |s|
43
51
  "kaz.july.7@gmail.com",
44
52
  "s.savulchik@gmail.com",
45
53
  "steve.agalloco@gmail.com",
46
- "akzhan.abdulin@gmail.com",
47
54
  "toby.net.info.mail+git@gmail.com",
55
+ "akzhan.abdulin@gmail.com",
56
+ "brooke@digitalocean.com",
48
57
  "bjoerge@bengler.no",
49
- "cheald@gmail.com"
58
+ "cheald@gmail.com",
59
+ "self@hecticjeff.net",
60
+ "coreyward@me.com",
61
+ "dario@uxtemple.com",
62
+ "dek-oss@gravitext.com"
50
63
  ]
51
64
 
52
65
  # generated from git ls-files
@@ -72,6 +85,7 @@ Gem::Specification.new do |s|
72
85
  "lib/rack/protection/xss_header.rb",
73
86
  "rack-protection.gemspec",
74
87
  "spec/authenticity_token_spec.rb",
88
+ "spec/base_spec.rb",
75
89
  "spec/escaped_params_spec.rb",
76
90
  "spec/form_token_spec.rb",
77
91
  "spec/frame_options_spec.rb",
@@ -30,4 +30,19 @@ describe Rack::Protection::AuthenticityToken do
30
30
  it "prevents ajax requests without a valid token" do
31
31
  post('/', {}, "HTTP_X_REQUESTED_WITH" => "XMLHttpRequest").should_not be_ok
32
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
33
48
  end
@@ -0,0 +1,9 @@
1
+ require File.expand_path('../spec_helper.rb', __FILE__)
2
+
3
+ describe Rack::Protection::Base do
4
+ describe "#random_string" do
5
+ it "outputs a string of 32 characters" do
6
+ described_class.new(lambda {}).random_string.length.should == 32
7
+ end
8
+ end
9
+ end
@@ -31,6 +31,7 @@ describe Rack::Protection::JsonCsrf do
31
31
  it "accepts XHR requests" do
32
32
  get('/', {}, 'HTTP_REFERER' => 'http://evil.com', 'HTTP_X_REQUESTED_WITH' => 'XMLHttpRequest').should be_ok
33
33
  end
34
+
34
35
  end
35
36
 
36
37
  describe 'not json response' do
@@ -41,4 +42,17 @@ describe Rack::Protection::JsonCsrf do
41
42
  end
42
43
 
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
44
58
  end
@@ -14,8 +14,8 @@ describe Rack::Protection::PathTraversal do
14
14
 
15
15
  { # yes, this is ugly, feel free to change that
16
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'
17
+ '/%2e.' => '/', '/a/%2E%2e/b' => '/b', '/a%2f%2E%2e%2Fb/' => '/b/',
18
+ '//' => '/', '/%2fetc%2Fpasswd' => '/etc/passwd'
19
19
  }.each do |a, b|
20
20
  it("replaces #{a.inspect} with #{b.inspect}") { get(a).body.should == b }
21
21
  end
@@ -25,4 +25,17 @@ describe Rack::Protection::PathTraversal do
25
25
  app.call({}).should be == 42
26
26
  end
27
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
28
41
  end
@@ -46,4 +46,25 @@ describe Rack::Protection do
46
46
  it { should be_false }
47
47
  end
48
48
  end
49
+
50
+ describe "#instrument" do
51
+ let(:env) { { 'rack.protection.attack' => 'base' } }
52
+ let(:instrumenter) { double('Instrumenter') }
53
+
54
+ after do
55
+ app.instrument(env)
56
+ end
57
+
58
+ context 'with an instrumenter specified' do
59
+ let(:app) { Rack::Protection::Base.new(nil, :instrumenter => instrumenter) }
60
+
61
+ it { instrumenter.should_receive(:instrument).with('rack.protection', env) }
62
+ end
63
+
64
+ context 'with no instrumenter specified' do
65
+ let(:app) { Rack::Protection::Base.new(nil) }
66
+
67
+ it { instrumenter.should_not_receive(:instrument) }
68
+ end
69
+ end
49
70
  end
metadata CHANGED
@@ -1,15 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rack-protection
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.5.0
5
- prerelease:
4
+ version: 1.5.1
6
5
  platform: ruby
7
6
  authors:
8
7
  - Konstantin Haase
9
8
  - Alex Rodionov
10
- - Chris Heald
11
- - Chris Mytton
12
- - Corey Ward
9
+ - Patrick Ellis
10
+ - Jeff Welling
11
+ - ITO Nobuaki
12
+ - Matteo Centenaro
13
13
  - David Kellum
14
14
  - Egor Homakov
15
15
  - Florian Gilcher
@@ -19,50 +19,50 @@ authors:
19
19
  - SAKAI, Kazuaki
20
20
  - Stanislav Savulchik
21
21
  - Steve Agalloco
22
- - Akzhan Abdulin
23
22
  - TOBY
23
+ - Akzhan Abdulin
24
+ - brookemckim
24
25
  - Bjørge Næss
26
+ - Chris Heald
27
+ - Chris Mytton
28
+ - Corey Ward
29
+ - Dario Cravero
25
30
  autorequire:
26
31
  bindir: bin
27
32
  cert_chain: []
28
- date: 2013-03-13 00:00:00.000000000 Z
33
+ date: 2013-10-21 00:00:00.000000000 Z
29
34
  dependencies:
30
35
  - !ruby/object:Gem::Dependency
31
36
  name: rack
32
37
  requirement: !ruby/object:Gem::Requirement
33
- none: false
34
38
  requirements:
35
- - - ! '>='
39
+ - - '>='
36
40
  - !ruby/object:Gem::Version
37
41
  version: '0'
38
42
  type: :runtime
39
43
  prerelease: false
40
44
  version_requirements: !ruby/object:Gem::Requirement
41
- none: false
42
45
  requirements:
43
- - - ! '>='
46
+ - - '>='
44
47
  - !ruby/object:Gem::Version
45
48
  version: '0'
46
49
  - !ruby/object:Gem::Dependency
47
50
  name: rack-test
48
51
  requirement: !ruby/object:Gem::Requirement
49
- none: false
50
52
  requirements:
51
- - - ! '>='
53
+ - - '>='
52
54
  - !ruby/object:Gem::Version
53
55
  version: '0'
54
56
  type: :development
55
57
  prerelease: false
56
58
  version_requirements: !ruby/object:Gem::Requirement
57
- none: false
58
59
  requirements:
59
- - - ! '>='
60
+ - - '>='
60
61
  - !ruby/object:Gem::Version
61
62
  version: '0'
62
63
  - !ruby/object:Gem::Dependency
63
64
  name: rspec
64
65
  requirement: !ruby/object:Gem::Requirement
65
- none: false
66
66
  requirements:
67
67
  - - ~>
68
68
  - !ruby/object:Gem::Version
@@ -70,7 +70,6 @@ dependencies:
70
70
  type: :development
71
71
  prerelease: false
72
72
  version_requirements: !ruby/object:Gem::Requirement
73
- none: false
74
73
  requirements:
75
74
  - - ~>
76
75
  - !ruby/object:Gem::Version
@@ -79,9 +78,10 @@ description: You should use protection!
79
78
  email:
80
79
  - konstantin.mailinglists@googlemail.com
81
80
  - p0deje@gmail.com
82
- - self@hecticjeff.net
83
- - coreyward@me.com
84
- - dek-oss@gravitext.com
81
+ - patrick@soundcloud.com
82
+ - jeff.welling@gmail.com
83
+ - bugant@gmail.com
84
+ - daydream.trippers@gmail.com
85
85
  - homakov@gmail.com
86
86
  - florian.gilcher@asquera.de
87
87
  - developer@fojasaur.us
@@ -90,10 +90,15 @@ email:
90
90
  - kaz.july.7@gmail.com
91
91
  - s.savulchik@gmail.com
92
92
  - steve.agalloco@gmail.com
93
- - akzhan.abdulin@gmail.com
94
93
  - toby.net.info.mail+git@gmail.com
94
+ - akzhan.abdulin@gmail.com
95
+ - brooke@digitalocean.com
95
96
  - bjoerge@bengler.no
96
97
  - cheald@gmail.com
98
+ - self@hecticjeff.net
99
+ - coreyward@me.com
100
+ - dario@uxtemple.com
101
+ - dek-oss@gravitext.com
97
102
  executables: []
98
103
  extensions: []
99
104
  extra_rdoc_files: []
@@ -119,6 +124,7 @@ files:
119
124
  - lib/rack/protection/xss_header.rb
120
125
  - rack-protection.gemspec
121
126
  - spec/authenticity_token_spec.rb
127
+ - spec/base_spec.rb
122
128
  - spec/escaped_params_spec.rb
123
129
  - spec/form_token_spec.rb
124
130
  - spec/frame_options_spec.rb
@@ -133,28 +139,28 @@ files:
133
139
  - spec/spec_helper.rb
134
140
  - spec/xss_header_spec.rb
135
141
  homepage: http://github.com/rkh/rack-protection
136
- licenses: []
142
+ licenses:
143
+ - MIT
144
+ metadata: {}
137
145
  post_install_message:
138
146
  rdoc_options: []
139
147
  require_paths:
140
148
  - lib
141
149
  required_ruby_version: !ruby/object:Gem::Requirement
142
- none: false
143
150
  requirements:
144
- - - ! '>='
151
+ - - '>='
145
152
  - !ruby/object:Gem::Version
146
153
  version: '0'
147
154
  required_rubygems_version: !ruby/object:Gem::Requirement
148
- none: false
149
155
  requirements:
150
- - - ! '>='
156
+ - - '>='
151
157
  - !ruby/object:Gem::Version
152
158
  version: '0'
153
159
  requirements: []
154
160
  rubyforge_project:
155
- rubygems_version: 1.8.23
161
+ rubygems_version: 2.0.7
156
162
  signing_key:
157
- specification_version: 3
163
+ specification_version: 4
158
164
  summary: You should use protection!
159
165
  test_files: []
160
166
  has_rdoc: