rack-protection 2.0.0 → 2.1.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 60b24d006884c214484d2d6275ddfd9a09719fe6
4
- data.tar.gz: b43b08983d4fc1fcf5525d28e0b704e49ee93a25
2
+ SHA256:
3
+ metadata.gz: a3268bb2b60f8095b38658717f5e267da2e1dfbee57f487baf39a185d3cf9266
4
+ data.tar.gz: fc40122b95963a81333da038536782d85a9abdc92b823eb5d3044ef3c5c807c4
5
5
  SHA512:
6
- metadata.gz: 926c434a0da749f9e615786c4600d7f3a933454ba179b4f3671d3abeb65d843281b95038258edaac3f01ae447c032aa8844141de0a399fd5447e6cbab12deac6
7
- data.tar.gz: 64892fdb92b20c537ffebbbc00d374e4d0bd07cf37dab25c21c95676b371477356c7ba3a52945e0f9a84b0db40bbd3fc964aa21a8525ed2bfac4dd3be204817f
6
+ metadata.gz: 7b381c903bb99d1e8cfcd00554642aafc2644f4432987be95e094a84b0f020648efb92b4a48e082cda5749045c44d14e5f08d97a1a733bf2b1e850eeaf69d67b
7
+ data.tar.gz: bfb60cf9484528f0096cd68a6da55b66fa3471407a120caff83ee961b54043f3e4aca45a219273e7e48cc85ce70742ee75dab750609239fb887dfc35dfbcae59
data/Gemfile CHANGED
@@ -1,4 +1,4 @@
1
- source "http://rubygems.org"
1
+ source "https://rubygems.org"
2
2
  # encoding: utf-8
3
3
 
4
4
  gem 'rake'
data/README.md CHANGED
@@ -1,7 +1,5 @@
1
1
  # Rack::Protection
2
2
 
3
- [![Build Status](https://secure.travis-ci.org/sinatra/rack-protection.png)](http://travis-ci.org/sinatra/rack-protection)
4
-
5
3
  This gem protects against typical web attacks.
6
4
  Should work for all Rack apps, including Rails.
7
5
 
@@ -40,55 +38,55 @@ run MyApp
40
38
 
41
39
  Prevented by:
42
40
 
43
- * `Rack::Protection::AuthenticityToken` (not included by `use Rack::Protection`)
44
- * `Rack::Protection::FormToken` (not included by `use Rack::Protection`)
45
- * `Rack::Protection::JsonCsrf`
46
- * `Rack::Protection::RemoteReferrer` (not included by `use Rack::Protection`)
47
- * `Rack::Protection::RemoteToken`
48
- * `Rack::Protection::HttpOrigin`
41
+ * [`Rack::Protection::AuthenticityToken`][authenticity-token] (not included by `use Rack::Protection`)
42
+ * [`Rack::Protection::FormToken`][form-token] (not included by `use Rack::Protection`)
43
+ * [`Rack::Protection::JsonCsrf`][json-csrf]
44
+ * [`Rack::Protection::RemoteReferrer`][remote-referrer] (not included by `use Rack::Protection`)
45
+ * [`Rack::Protection::RemoteToken`][remote-token]
46
+ * [`Rack::Protection::HttpOrigin`][http-origin]
49
47
 
50
48
  ## Cross Site Scripting
51
49
 
52
50
  Prevented by:
53
51
 
54
- * `Rack::Protection::EscapedParams` (not included by `use Rack::Protection`)
55
- * `Rack::Protection::XSSHeader` (Internet Explorer and Chrome only)
56
- * `Rack::Protection::ContentSecurityPolicy`
52
+ * [`Rack::Protection::EscapedParams`][escaped-params] (not included by `use Rack::Protection`)
53
+ * [`Rack::Protection::XSSHeader`][xss-header] (Internet Explorer and Chrome only)
54
+ * [`Rack::Protection::ContentSecurityPolicy`][content-security-policy]
57
55
 
58
56
  ## Clickjacking
59
57
 
60
58
  Prevented by:
61
59
 
62
- * `Rack::Protection::FrameOptions`
60
+ * [`Rack::Protection::FrameOptions`][frame-options]
63
61
 
64
62
  ## Directory Traversal
65
63
 
66
64
  Prevented by:
67
65
 
68
- * `Rack::Protection::PathTraversal`
66
+ * [`Rack::Protection::PathTraversal`][path-traversal]
69
67
 
70
68
  ## Session Hijacking
71
69
 
72
70
  Prevented by:
73
71
 
74
- * `Rack::Protection::SessionHijacking`
72
+ * [`Rack::Protection::SessionHijacking`][session-hijacking]
75
73
 
76
74
  ## Cookie Tossing
77
75
 
78
76
  Prevented by:
79
- * `Rack::Protection::CookieTossing` (not included by `use Rack::Protection`)
77
+ * [`Rack::Protection::CookieTossing`][cookie-tossing] (not included by `use Rack::Protection`)
80
78
 
81
79
  ## IP Spoofing
82
80
 
83
81
  Prevented by:
84
82
 
85
- * `Rack::Protection::IPSpoofing`
83
+ * [`Rack::Protection::IPSpoofing`][ip-spoofing]
86
84
 
87
85
  ## Helps to protect against protocol downgrade attacks and cookie hijacking
88
86
 
89
87
  Prevented by:
90
88
 
91
- * `Rack::Protection::StrictTransport` (not included by `use Rack::Protection`)
89
+ * [`Rack::Protection::StrictTransport`][strict-transport] (not included by `use Rack::Protection`)
92
90
 
93
91
  # Installation
94
92
 
@@ -102,3 +100,19 @@ use Rack::Protection, instrumenter: ActiveSupport::Notifications
102
100
  ```
103
101
 
104
102
  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'.
103
+
104
+ [authenticity-token]: http://www.sinatrarb.com/protection/authenticity_token
105
+ [content-security-policy]: http://www.sinatrarb.com/protection/content_security_policy
106
+ [cookie-tossing]: http://www.sinatrarb.com/protection/cookie_tossing
107
+ [escaped-params]: http://www.sinatrarb.com/protection/escaped_params
108
+ [form-token]: http://www.sinatrarb.com/protection/form_token
109
+ [frame-options]: http://www.sinatrarb.com/protection/frame_options
110
+ [http-origin]: http://www.sinatrarb.com/protection/http_origin
111
+ [ip-spoofing]: http://www.sinatrarb.com/protection/ip_spoofing
112
+ [json-csrf]: http://www.sinatrarb.com/protection/json_csrf
113
+ [path-traversal]: http://www.sinatrarb.com/protection/path_traversal
114
+ [remote-referrer]: http://www.sinatrarb.com/protection/remote_referrer
115
+ [remote-token]: http://www.sinatrarb.com/protection/remote_token
116
+ [session-hijacking]: http://www.sinatrarb.com/protection/session_hijacking
117
+ [strict-transport]: http://www.sinatrarb.com/protection/strict_transport
118
+ [xss-header]: http://www.sinatrarb.com/protection/xss_header
data/Rakefile CHANGED
@@ -24,7 +24,15 @@ namespace :doc do
24
24
  end
25
25
  end
26
26
 
27
- task :all => [:readmes]
27
+ task :index do
28
+ doc = File.read("README.md")
29
+ file = "doc/rack-protection-readme.md"
30
+ Dir.mkdir "doc" unless File.directory? "doc"
31
+ puts "writing #{file}"
32
+ File.open(file, "w") { |f| f << doc }
33
+ end
34
+
35
+ task :all => [:readmes, :index]
28
36
  end
29
37
 
30
38
  desc "generate documentation"
@@ -14,6 +14,7 @@ module Rack
14
14
  autoload :IPSpoofing, 'rack/protection/ip_spoofing'
15
15
  autoload :JsonCsrf, 'rack/protection/json_csrf'
16
16
  autoload :PathTraversal, 'rack/protection/path_traversal'
17
+ autoload :ReferrerPolicy, 'rack/protection/referrer_policy'
17
18
  autoload :RemoteReferrer, 'rack/protection/remote_referrer'
18
19
  autoload :RemoteToken, 'rack/protection/remote_token'
19
20
  autoload :SessionHijacking, 'rack/protection/session_hijacking'
@@ -32,9 +33,11 @@ module Rack
32
33
  Rack::Builder.new do
33
34
  # Off by default, unless added
34
35
  use ::Rack::Protection::AuthenticityToken, options if use_these.include? :authenticity_token
35
- use ::Rack::Protection::CookieTossing, options if use_these.include? :cookie_tossing
36
36
  use ::Rack::Protection::ContentSecurityPolicy, options if use_these.include? :content_security_policy
37
+ use ::Rack::Protection::CookieTossing, options if use_these.include? :cookie_tossing
38
+ use ::Rack::Protection::EscapedParams, options if use_these.include? :escaped_params
37
39
  use ::Rack::Protection::FormToken, options if use_these.include? :form_token
40
+ use ::Rack::Protection::ReferrerPolicy, options if use_these.include? :referrer_policy
38
41
  use ::Rack::Protection::RemoteReferrer, options if use_these.include? :remote_referrer
39
42
  use ::Rack::Protection::StrictTransport, options if use_these.include? :strict_transport
40
43
 
@@ -9,14 +9,78 @@ module Rack
9
9
  # Supported browsers:: all
10
10
  # More infos:: http://en.wikipedia.org/wiki/Cross-site_request_forgery
11
11
  #
12
- # Only accepts unsafe HTTP requests if a given access token matches the token
13
- # included in the session.
12
+ # This middleware only accepts requests other than <tt>GET</tt>,
13
+ # <tt>HEAD</tt>, <tt>OPTIONS</tt>, <tt>TRACE</tt> if their given access
14
+ # token matches the token included in the session.
14
15
  #
15
- # Compatible with rack-csrf.
16
+ # It checks the <tt>X-CSRF-Token</tt> header and the <tt>POST</tt> form
17
+ # data.
16
18
  #
17
- # Options:
19
+ # Compatible with the {rack-csrf}[https://rubygems.org/gems/rack_csrf] gem.
18
20
  #
19
- # authenticity_param: Defines the param's name that should contain the token on a request.
21
+ # == Options
22
+ #
23
+ # [<tt>:authenticity_param</tt>] the name of the param that should contain
24
+ # the token on a request. Default value:
25
+ # <tt>"authenticity_token"</tt>
26
+ #
27
+ # == Example: Forms application
28
+ #
29
+ # To show what the AuthenticityToken does, this section includes a sample
30
+ # program which shows two forms. One with, and one without a CSRF token
31
+ # The one without CSRF token field will get a 403 Forbidden response.
32
+ #
33
+ # Install the gem, then run the program:
34
+ #
35
+ # gem install 'rack-protection'
36
+ # ruby server.rb
37
+ #
38
+ # Here is <tt>server.rb</tt>:
39
+ #
40
+ # require 'rack/protection'
41
+ #
42
+ # app = Rack::Builder.app do
43
+ # use Rack::Session::Cookie, secret: 'secret'
44
+ # use Rack::Protection::AuthenticityToken
45
+ #
46
+ # run -> (env) do
47
+ # [200, {}, [
48
+ # <<~EOS
49
+ # <!DOCTYPE html>
50
+ # <html lang="en">
51
+ # <head>
52
+ # <meta charset="UTF-8" />
53
+ # <title>rack-protection minimal example</title>
54
+ # </head>
55
+ # <body>
56
+ # <h1>Without Authenticity Token</h1>
57
+ # <p>This takes you to <tt>Forbidden</tt></p>
58
+ # <form action="" method="post">
59
+ # <input type="text" name="foo" />
60
+ # <input type="submit" />
61
+ # </form>
62
+ #
63
+ # <h1>With Authenticity Token</h1>
64
+ # <p>This successfully takes you to back to this form.</p>
65
+ # <form action="" method="post">
66
+ # <input type="hidden" name="authenticity_token" value="#{Rack::Protection::AuthenticityToken.token(env['rack.session'])}" />
67
+ # <input type="text" name="foo" />
68
+ # <input type="submit" />
69
+ # </form>
70
+ # </body>
71
+ # </html>
72
+ # EOS
73
+ # ]]
74
+ # end
75
+ # end
76
+ #
77
+ # Rack::Handler::WEBrick.run app
78
+ #
79
+ # == Example: Customize which POST parameter holds the token
80
+ #
81
+ # To customize the authenticity parameter for form data, use the
82
+ # <tt>:authenticity_param</tt> option:
83
+ # use Rack::Protection::AuthenticityToken, authenticity_param: 'your_token_param_name'
20
84
  class AuthenticityToken < Base
21
85
  TOKEN_LENGTH = 32
22
86
 
@@ -125,7 +189,14 @@ module Rack
125
189
  end
126
190
 
127
191
  def xor_byte_strings(s1, s2)
128
- s1.bytes.zip(s2.bytes).map { |(c1,c2)| c1 ^ c2 }.pack('c*')
192
+ s2 = s2.dup
193
+ size = s1.bytesize
194
+ i = 0
195
+ while i < size
196
+ s2.setbyte(i, s1.getbyte(i) ^ s2.getbyte(i))
197
+ i += 1
198
+ end
199
+ s2
129
200
  end
130
201
  end
131
202
  end
@@ -13,7 +13,7 @@ module Rack
13
13
  :session_key => 'rack.session', :status => 403,
14
14
  :allow_empty_referrer => true,
15
15
  :report_key => "protection.failed",
16
- :html_types => %w[text/html application/xhtml]
16
+ :html_types => %w[text/html application/xhtml text/xml application/xml]
17
17
  }
18
18
 
19
19
  attr_reader :app, :options
@@ -36,16 +36,15 @@ module Rack
36
36
  # to be used in a policy.
37
37
  #
38
38
  class ContentSecurityPolicy < Base
39
- default_options default_src: :none, script_src: "'self'",
40
- img_src: "'self'", style_src: "'self'",
41
- connect_src: "'self'", report_only: false
39
+ default_options default_src: "'self'", report_only: false
42
40
 
43
41
  DIRECTIVES = %i(base_uri child_src connect_src default_src
44
42
  font_src form_action frame_ancestors frame_src
45
43
  img_src manifest_src media_src object_src
46
44
  plugin_types referrer reflected_xss report_to
47
45
  report_uri require_sri_for sandbox script_src
48
- style_src worker_src).freeze
46
+ style_src worker_src webrtc_src navigate_to
47
+ prefetch_src).freeze
49
48
 
50
49
  NO_ARG_DIRECTIVES = %i(block_all_mixed_content disown_opener
51
50
  upgrade_insecure_requests).freeze
@@ -62,7 +61,7 @@ module Rack
62
61
  # Set these key values to boolean 'true' to include in policy
63
62
  NO_ARG_DIRECTIVES.each do |d|
64
63
  if options.key?(d) && options[d].is_a?(TrueClass)
65
- directives << d.to_s.sub(/_/, '-')
64
+ directives << d.to_s.tr('_', '-')
66
65
  end
67
66
  end
68
67
 
@@ -9,11 +9,11 @@ module Rack
9
9
  # http://tools.ietf.org/html/draft-abarth-origin
10
10
  #
11
11
  # Does not accept unsafe HTTP requests when value of Origin HTTP request header
12
- # does not match default or whitelisted URIs.
12
+ # does not match default or permitted URIs.
13
13
  #
14
- # If you want to whitelist a specific domain, you can pass in as the `:origin_whitelist` option:
14
+ # If you want to permit a specific domain, you can pass in as the `:permitted_origins` option:
15
15
  #
16
- # use Rack::Protection, origin_whitelist: ["http://localhost:3000", "http://127.0.01:3000"]
16
+ # use Rack::Protection, permitted_origins: ["http://localhost:3000", "http://127.0.01:3000"]
17
17
  #
18
18
  # The `:allow_if` option can also be set to a proc to use custom allow/deny logic.
19
19
  class HttpOrigin < Base
@@ -32,7 +32,14 @@ module Rack
32
32
  return true unless origin = env['HTTP_ORIGIN']
33
33
  return true if base_url(env) == origin
34
34
  return true if options[:allow_if] && options[:allow_if].call(env)
35
- Array(options[:origin_whitelist]).include? origin
35
+
36
+ if options.key? :origin_whitelist
37
+ warn "Rack::Protection origin_whitelist option is deprecated and will be removed, " \
38
+ "use permitted_origins instead.\n"
39
+ end
40
+
41
+ permitted_origins = options[:permitted_origins] || options[:origin_whitelist]
42
+ Array(permitted_origins).include? origin
36
43
  end
37
44
 
38
45
  end
@@ -19,19 +19,14 @@ 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
22
+ encoding = path.encoding
23
+ dot = '.'.encode(encoding)
24
+ slash = '/'.encode(encoding)
25
+ backslash = '\\'.encode(encoding)
32
26
 
33
27
  parts = []
34
- unescaped = path.gsub(/%2e/i, dot).gsub(/%2f/i, slash)
28
+ unescaped = path.gsub(/%2e/i, dot).gsub(/%2f/i, slash).gsub(/%5c/i, backslash)
29
+ unescaped = unescaped.gsub(backslash, slash)
35
30
 
36
31
  unescaped.split(slash).each do |part|
37
32
  next if part.empty? or part == dot
@@ -0,0 +1,25 @@
1
+ require 'rack/protection'
2
+
3
+ module Rack
4
+ module Protection
5
+ ##
6
+ # Prevented attack:: Secret leakage, third party tracking
7
+ # Supported browsers:: mixed support
8
+ # More infos:: https://www.w3.org/TR/referrer-policy/
9
+ # https://caniuse.com/#search=referrer-policy
10
+ #
11
+ # Sets Referrer-Policy header to tell the browser to limit the Referer header.
12
+ #
13
+ # Options:
14
+ # referrer_policy:: The policy to use (default: 'strict-origin-when-cross-origin')
15
+ class ReferrerPolicy < Base
16
+ default_options :referrer_policy => 'strict-origin-when-cross-origin'
17
+
18
+ def call(env)
19
+ status, headers, body = @app.call(env)
20
+ headers['Referrer-Policy'] ||= options[:referrer_policy]
21
+ [status, headers, body]
22
+ end
23
+ end
24
+ end
25
+ end
@@ -14,7 +14,7 @@ module Rack
14
14
  class SessionHijacking < Base
15
15
  default_reaction :drop_session
16
16
  default_options :tracking_key => :tracking, :encrypt_tracking => true,
17
- :track => %w[HTTP_USER_AGENT HTTP_ACCEPT_LANGUAGE]
17
+ :track => %w[HTTP_USER_AGENT]
18
18
 
19
19
  def accepts?(env)
20
20
  session = session env
@@ -1,5 +1,5 @@
1
1
  module Rack
2
2
  module Protection
3
- VERSION = '2.0.0'
3
+ VERSION = '2.1.0'
4
4
  end
5
5
  end
@@ -5,7 +5,7 @@ Gem::Specification.new do |s|
5
5
  s.name = "rack-protection"
6
6
  s.version = version
7
7
  s.description = "Protect against typical web attacks, works with all Rack apps, including Rails."
8
- s.homepage = "http://github.com/sinatra/sinatra/tree/master/rack-protection"
8
+ s.homepage = "http://sinatrarb.com/protection/"
9
9
  s.summary = s.description
10
10
  s.license = 'MIT'
11
11
  s.authors = ["https://github.com/sinatra/sinatra/graphs/contributors"]
@@ -18,8 +18,23 @@ Gem::Specification.new do |s|
18
18
  "rack-protection.gemspec"
19
19
  ]
20
20
 
21
+ if s.respond_to?(:metadata)
22
+ s.metadata = {
23
+ 'source_code_uri' => 'https://github.com/sinatra/sinatra/tree/master/rack-protection',
24
+ 'homepage_uri' => 'http://sinatrarb.com/protection/',
25
+ 'documentation_uri' => 'https://www.rubydoc.info/gems/rack-protection'
26
+ }
27
+ else
28
+ raise <<-EOF
29
+ RubyGems 2.0 or newer is required to protect against public gem pushes. You can update your rubygems version by running:
30
+ gem install rubygems-update
31
+ update_rubygems:
32
+ gem update --system
33
+ EOF
34
+ end
35
+
21
36
  # dependencies
22
37
  s.add_dependency "rack"
23
38
  s.add_development_dependency "rack-test"
24
- s.add_development_dependency "rspec", "~> 3.0.0"
39
+ s.add_development_dependency "rspec", "~> 3.6"
25
40
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rack-protection
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.0
4
+ version: 2.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - https://github.com/sinatra/sinatra/graphs/contributors
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-05-07 00:00:00.000000000 Z
11
+ date: 2020-09-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rack
@@ -44,14 +44,14 @@ dependencies:
44
44
  requirements:
45
45
  - - "~>"
46
46
  - !ruby/object:Gem::Version
47
- version: 3.0.0
47
+ version: '3.6'
48
48
  type: :development
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
52
  - - "~>"
53
53
  - !ruby/object:Gem::Version
54
- version: 3.0.0
54
+ version: '3.6'
55
55
  description: Protect against typical web attacks, works with all Rack apps, including
56
56
  Rails.
57
57
  email: sinatrarb@googlegroups.com
@@ -76,6 +76,7 @@ files:
76
76
  - lib/rack/protection/ip_spoofing.rb
77
77
  - lib/rack/protection/json_csrf.rb
78
78
  - lib/rack/protection/path_traversal.rb
79
+ - lib/rack/protection/referrer_policy.rb
79
80
  - lib/rack/protection/remote_referrer.rb
80
81
  - lib/rack/protection/remote_token.rb
81
82
  - lib/rack/protection/session_hijacking.rb
@@ -83,10 +84,13 @@ files:
83
84
  - lib/rack/protection/version.rb
84
85
  - lib/rack/protection/xss_header.rb
85
86
  - rack-protection.gemspec
86
- homepage: http://github.com/sinatra/sinatra/tree/master/rack-protection
87
+ homepage: http://sinatrarb.com/protection/
87
88
  licenses:
88
89
  - MIT
89
- metadata: {}
90
+ metadata:
91
+ source_code_uri: https://github.com/sinatra/sinatra/tree/master/rack-protection
92
+ homepage_uri: http://sinatrarb.com/protection/
93
+ documentation_uri: https://www.rubydoc.info/gems/rack-protection
90
94
  post_install_message:
91
95
  rdoc_options: []
92
96
  require_paths:
@@ -102,8 +106,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
102
106
  - !ruby/object:Gem::Version
103
107
  version: '0'
104
108
  requirements: []
105
- rubyforge_project:
106
- rubygems_version: 2.6.11
109
+ rubygems_version: 3.1.2
107
110
  signing_key:
108
111
  specification_version: 4
109
112
  summary: Protect against typical web attacks, works with all Rack apps, including