rack-protection 1.5.0 → 1.5.1

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.

@@ -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: