rack-protection 2.0.0 → 2.2.0

Sign up to get free protection for your applications and to get access to all the features.
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: 5ed141bb1184b6760816e1768b5d91246d91a01ef56cb17a163f5370df604026
4
+ data.tar.gz: f3ac32c5d25123bb9f5843a47ca17dc796a9e3469a997f32b772ab72200cff58
5
5
  SHA512:
6
- metadata.gz: 926c434a0da749f9e615786c4600d7f3a933454ba179b4f3671d3abeb65d843281b95038258edaac3f01ae447c032aa8844141de0a399fd5447e6cbab12deac6
7
- data.tar.gz: 64892fdb92b20c537ffebbbc00d374e4d0bd07cf37dab25c21c95676b371477356c7ba3a52945e0f9a84b0db40bbd3fc964aa21a8525ed2bfac4dd3be204817f
6
+ metadata.gz: 9d78cedbd03ffe9dba1c6bca4e4b3cf2b165b12e9befb1136bda35651e99b88ecd575a44e3f394aee8e0191f7080706ebc1a2462dc5504b19d41a3b7bb47e80b
7
+ data.tar.gz: 00466e987ae67ebd7b76be1099a99cba4852987b88dbbccf4f230b1d3ee8dfa40f627cc0463aec39d64788566e08cb71117a5c33688edbb30540949436245f56
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"
@@ -1,5 +1,6 @@
1
1
  require 'rack/protection'
2
2
  require 'securerandom'
3
+ require 'openssl'
3
4
  require 'base64'
4
5
 
5
6
  module Rack
@@ -9,54 +10,140 @@ module Rack
9
10
  # Supported browsers:: all
10
11
  # More infos:: http://en.wikipedia.org/wiki/Cross-site_request_forgery
11
12
  #
12
- # Only accepts unsafe HTTP requests if a given access token matches the token
13
- # included in the session.
13
+ # This middleware only accepts requests other than <tt>GET</tt>,
14
+ # <tt>HEAD</tt>, <tt>OPTIONS</tt>, <tt>TRACE</tt> if their given access
15
+ # token matches the token included in the session.
14
16
  #
15
- # Compatible with rack-csrf.
17
+ # It checks the <tt>X-CSRF-Token</tt> header and the <tt>POST</tt> form
18
+ # data.
16
19
  #
17
- # Options:
20
+ # Compatible with the {rack-csrf}[https://rubygems.org/gems/rack_csrf] gem.
18
21
  #
19
- # authenticity_param: Defines the param's name that should contain the token on a request.
22
+ # == Options
23
+ #
24
+ # [<tt>:authenticity_param</tt>] the name of the param that should contain
25
+ # the token on a request. Default value:
26
+ # <tt>"authenticity_token"</tt>
27
+ #
28
+ # [<tt>:key</tt>] the name of the param that should contain
29
+ # the token in the session. Default value:
30
+ # <tt>:csrf</tt>
31
+ #
32
+ # [<tt>:allow_if</tt>] a proc for custom allow/deny logic. Default value:
33
+ # <tt>nil</tt>
34
+ #
35
+ # == Example: Forms application
36
+ #
37
+ # To show what the AuthenticityToken does, this section includes a sample
38
+ # program which shows two forms. One with, and one without a CSRF token
39
+ # The one without CSRF token field will get a 403 Forbidden response.
40
+ #
41
+ # Install the gem, then run the program:
42
+ #
43
+ # gem install 'rack-protection'
44
+ # ruby server.rb
45
+ #
46
+ # Here is <tt>server.rb</tt>:
47
+ #
48
+ # require 'rack/protection'
49
+ #
50
+ # app = Rack::Builder.app do
51
+ # use Rack::Session::Cookie, secret: 'secret'
52
+ # use Rack::Protection::AuthenticityToken
53
+ #
54
+ # run -> (env) do
55
+ # [200, {}, [
56
+ # <<~EOS
57
+ # <!DOCTYPE html>
58
+ # <html lang="en">
59
+ # <head>
60
+ # <meta charset="UTF-8" />
61
+ # <title>rack-protection minimal example</title>
62
+ # </head>
63
+ # <body>
64
+ # <h1>Without Authenticity Token</h1>
65
+ # <p>This takes you to <tt>Forbidden</tt></p>
66
+ # <form action="" method="post">
67
+ # <input type="text" name="foo" />
68
+ # <input type="submit" />
69
+ # </form>
70
+ #
71
+ # <h1>With Authenticity Token</h1>
72
+ # <p>This successfully takes you to back to this form.</p>
73
+ # <form action="" method="post">
74
+ # <input type="hidden" name="authenticity_token" value="#{Rack::Protection::AuthenticityToken.token(env['rack.session'])}" />
75
+ # <input type="text" name="foo" />
76
+ # <input type="submit" />
77
+ # </form>
78
+ # </body>
79
+ # </html>
80
+ # EOS
81
+ # ]]
82
+ # end
83
+ # end
84
+ #
85
+ # Rack::Handler::WEBrick.run app
86
+ #
87
+ # == Example: Customize which POST parameter holds the token
88
+ #
89
+ # To customize the authenticity parameter for form data, use the
90
+ # <tt>:authenticity_param</tt> option:
91
+ # use Rack::Protection::AuthenticityToken, authenticity_param: 'your_token_param_name'
20
92
  class AuthenticityToken < Base
21
93
  TOKEN_LENGTH = 32
22
94
 
23
95
  default_options :authenticity_param => 'authenticity_token',
96
+ :key => :csrf,
24
97
  :allow_if => nil
25
98
 
26
- def self.token(session)
27
- self.new(nil).mask_authenticity_token(session)
99
+ def self.token(session, path: nil, method: :post)
100
+ self.new(nil).mask_authenticity_token(session, path: path, method: method)
28
101
  end
29
102
 
30
103
  def self.random_token
31
- SecureRandom.base64(TOKEN_LENGTH)
104
+ SecureRandom.urlsafe_base64(TOKEN_LENGTH, padding: false)
32
105
  end
33
106
 
34
107
  def accepts?(env)
35
- session = session env
108
+ session = session(env)
36
109
  set_token(session)
37
110
 
38
111
  safe?(env) ||
39
- valid_token?(session, env['HTTP_X_CSRF_TOKEN']) ||
40
- valid_token?(session, Request.new(env).params[options[:authenticity_param]]) ||
112
+ valid_token?(env, env['HTTP_X_CSRF_TOKEN']) ||
113
+ valid_token?(env, Request.new(env).params[options[:authenticity_param]]) ||
41
114
  ( options[:allow_if] && options[:allow_if].call(env) )
115
+ rescue
116
+ false
42
117
  end
43
118
 
44
- def mask_authenticity_token(session)
45
- token = set_token(session)
119
+ def mask_authenticity_token(session, path: nil, method: :post)
120
+ set_token(session)
121
+
122
+ token = if path && method
123
+ per_form_token(session, path, method)
124
+ else
125
+ global_token(session)
126
+ end
127
+
46
128
  mask_token(token)
47
129
  end
48
130
 
131
+ GLOBAL_TOKEN_IDENTIFIER = '!real_csrf_token'
132
+ private_constant :GLOBAL_TOKEN_IDENTIFIER
133
+
49
134
  private
50
135
 
51
136
  def set_token(session)
52
- session[:csrf] ||= self.class.random_token
137
+ session[options[:key]] ||= self.class.random_token
53
138
  end
54
139
 
55
140
  # Checks the client's masked token to see if it matches the
56
141
  # session token.
57
- def valid_token?(session, token)
142
+ def valid_token?(env, token)
58
143
  return false if token.nil? || token.empty?
59
144
 
145
+ session = session(env)
146
+
60
147
  begin
61
148
  token = decode_token(token)
62
149
  rescue ArgumentError # encoded_masked_token is invalid Base64
@@ -67,13 +154,13 @@ module Rack
67
154
  # to handle any unmasked tokens that we've issued without error.
68
155
 
69
156
  if unmasked_token?(token)
70
- compare_with_real_token token, session
71
-
157
+ compare_with_real_token(token, session)
72
158
  elsif masked_token?(token)
73
159
  token = unmask_token(token)
74
160
 
75
- compare_with_real_token token, session
76
-
161
+ compare_with_global_token(token, session) ||
162
+ compare_with_real_token(token, session) ||
163
+ compare_with_per_form_token(token, session, Request.new(env))
77
164
  else
78
165
  false # Token is malformed
79
166
  end
@@ -83,7 +170,6 @@ module Rack
83
170
  # on each request. The masking is used to mitigate SSL attacks
84
171
  # like BREACH.
85
172
  def mask_token(token)
86
- token = decode_token(token)
87
173
  one_time_pad = SecureRandom.random_bytes(token.length)
88
174
  encrypted_token = xor_byte_strings(one_time_pad, token)
89
175
  masked_token = one_time_pad + encrypted_token
@@ -112,20 +198,53 @@ module Rack
112
198
  secure_compare(token, real_token(session))
113
199
  end
114
200
 
201
+ def compare_with_global_token(token, session)
202
+ secure_compare(token, global_token(session))
203
+ end
204
+
205
+ def compare_with_per_form_token(token, session, request)
206
+ secure_compare(token,
207
+ per_form_token(session, request.path.chomp('/'), request.request_method)
208
+ )
209
+ end
210
+
115
211
  def real_token(session)
116
- decode_token(session[:csrf])
212
+ decode_token(session[options[:key]])
213
+ end
214
+
215
+ def global_token(session)
216
+ token_hmac(session, GLOBAL_TOKEN_IDENTIFIER)
217
+ end
218
+
219
+ def per_form_token(session, path, method)
220
+ token_hmac(session, "#{path}##{method.downcase}")
117
221
  end
118
222
 
119
223
  def encode_token(token)
120
- Base64.strict_encode64(token)
224
+ Base64.urlsafe_encode64(token)
121
225
  end
122
226
 
123
227
  def decode_token(token)
124
- Base64.strict_decode64(token)
228
+ Base64.urlsafe_decode64(token)
229
+ end
230
+
231
+ def token_hmac(session, identifier)
232
+ OpenSSL::HMAC.digest(
233
+ OpenSSL::Digest::SHA256.new,
234
+ real_token(session),
235
+ identifier
236
+ )
125
237
  end
126
238
 
127
239
  def xor_byte_strings(s1, s2)
128
- s1.bytes.zip(s2.bytes).map { |(c1,c2)| c1 ^ c2 }.pack('c*')
240
+ s2 = s2.dup
241
+ size = s1.bytesize
242
+ i = 0
243
+ while i < size
244
+ s2.setbyte(i, s1.getbyte(i) ^ s2.getbyte(i))
245
+ i += 1
246
+ end
247
+ s2
129
248
  end
130
249
  end
131
250
  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 env, "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.2.0'
4
4
  end
5
5
  end
@@ -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
 
@@ -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.2.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: 2022-02-15 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