actionpack 6.0.3.7 → 6.0.4.1

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of actionpack might be problematic. Click here for more details.

checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 689cadf2c5055a30bce24daa0dbd2c5f4e9b62b8e05f318527556df6a1bbc0bd
4
- data.tar.gz: db971eb4537c26d3c61aaeb5933a936ab80465ab7533c3a1fd96fed34bc98159
3
+ metadata.gz: a1ce7e505c443ac3626576f8ee7d9f877df0f805a2f200993f67d377ffb39637
4
+ data.tar.gz: 63c9a462a845c3775f90d60d4a7554c3ec67c9090d67199210cf9978f8117469
5
5
  SHA512:
6
- metadata.gz: bb3325660659b91dd7917b48dfd211078d28812bfae7695e224599573835d7c42994ead64ebeb5c121d1dbc4ac30da9ae0f3a0be304892c914ce2309d8b3fc2b
7
- data.tar.gz: 826160c64038886b1bc08301f8d4782cd1564f5b167d452bd87b8870043581dc971bb9f5a54075001fe254148fc8845187f660f4cf4fcb84f5dfdf17bfb85dda
6
+ metadata.gz: b38a9f6e715de35d394eae37a599abf39e277b3f87916b648ede6489d499c9c638408f6d874eb47a22ce1b1fcf6eeac682125bbec92881b90002baf838df0e7e
7
+ data.tar.gz: 28abb4b6e0e463cba47474ea4e2c7d6c5fded3f4bace5853a32acdfd36bc0ebcaa699ea5c7444c5ca9a98210d23f7d63660c9237ba0389ffe2647e22d95d52e3
data/CHANGELOG.md CHANGED
@@ -1,3 +1,39 @@
1
+ ## Rails 6.0.4.1 (August 19, 2021) ##
2
+
3
+ * [CVE-2021-22942] Fix possible open redirect in Host Authorization middleware.
4
+
5
+ Specially crafted "X-Forwarded-Host" headers in combination with certain
6
+ "allowed host" formats can cause the Host Authorization middleware in Action
7
+ Pack to redirect users to a malicious website.
8
+
9
+ ## Rails 6.0.4 (June 15, 2021) ##
10
+
11
+ * Accept base64_urlsafe CSRF tokens to make forward compatible.
12
+
13
+ Base64 strict-encoded CSRF tokens are not inherently websafe, which makes
14
+ them difficult to deal with. For example, the common practice of sending
15
+ the CSRF token to a browser in a client-readable cookie does not work properly
16
+ out of the box: the value has to be url-encoded and decoded to survive transport.
17
+
18
+ In Rails 6.1, we generate Base64 urlsafe-encoded CSRF tokens, which are inherently
19
+ safe to transport. Validation accepts both urlsafe tokens, and strict-encoded
20
+ tokens for backwards compatibility.
21
+
22
+ In Rails 5.2.5, the CSRF token format is accidentally changed to urlsafe-encoded.
23
+ If you upgrade apps from 5.2.5, set the config `urlsafe_csrf_tokens = true`.
24
+
25
+ ```ruby
26
+ Rails.application.config.action_controller.urlsafe_csrf_tokens = true
27
+ ```
28
+
29
+ *Scott Blum*, *Étienne Barrié*
30
+
31
+ * Signed and encrypted cookies can now store `false` as their value when
32
+ `action_dispatch.use_cookies_with_metadata` is enabled.
33
+
34
+ *Rolandas Barysas*
35
+
36
+
1
37
  ## Rails 6.0.3.7 (May 05, 2021) ##
2
38
 
3
39
  * Prevent catastrophic backtracking during mime parsing
@@ -53,6 +89,7 @@
53
89
 
54
90
  * [CVE-2020-8164] Return self when calling #each, #each_pair, and #each_value instead of the raw @parameters hash
55
91
 
92
+
56
93
  ## Rails 6.0.3 (May 06, 2020) ##
57
94
 
58
95
  * Include child session assertion count in ActionDispatch::IntegrationTest
data/README.rdoc CHANGED
@@ -33,7 +33,7 @@ The latest version of Action Pack can be installed with RubyGems:
33
33
 
34
34
  Source code can be downloaded as part of the Rails project on GitHub:
35
35
 
36
- * https://github.com/rails/rails/tree/master/actionpack
36
+ * https://github.com/rails/rails/tree/main/actionpack
37
37
 
38
38
 
39
39
  == License
@@ -275,7 +275,10 @@ module ActionController
275
275
  return false unless request.has_content_type?
276
276
 
277
277
  ref = request.content_mime_type.ref
278
+
278
279
  _wrapper_formats.include?(ref) && _wrapper_key && !request.parameters.key?(_wrapper_key)
280
+ rescue ActionDispatch::Http::Parameters::ParseError
281
+ false
279
282
  end
280
283
 
281
284
  def _perform_parameter_wrapping
@@ -289,8 +292,6 @@ module ActionController
289
292
 
290
293
  # This will display the wrapped hash in the log file.
291
294
  request.filtered_parameters.merge! wrapped_filtered_hash
292
- rescue ActionDispatch::Http::Parameters::ParseError
293
- # swallow parse error exception
294
295
  end
295
296
  end
296
297
  end
@@ -32,29 +32,21 @@ module ActionController #:nodoc:
32
32
  # response may be extracted. To prevent this, only XmlHttpRequest (known as XHR or
33
33
  # Ajax) requests are allowed to make requests for JavaScript responses.
34
34
  #
35
- # It's important to remember that XML or JSON requests are also checked by default. If
36
- # you're building an API or an SPA you could change forgery protection method in
37
- # <tt>ApplicationController</tt> (by default: <tt>:exception</tt>):
35
+ # Subclasses of <tt>ActionController::Base</tt> are protected by default with the
36
+ # <tt>:exception</tt> strategy, which raises an
37
+ # <tt>ActionController::InvalidAuthenticityToken</tt> error on unverified requests.
38
+ #
39
+ # APIs may want to disable this behavior since they are typically designed to be
40
+ # state-less: that is, the request API client handles the session instead of Rails.
41
+ # One way to achieve this is to use the <tt>:null_session</tt> strategy instead,
42
+ # which allows unverified requests to be handled, but with an empty session:
38
43
  #
39
44
  # class ApplicationController < ActionController::Base
40
- # protect_from_forgery unless: -> { request.format.json? }
45
+ # protect_from_forgery with: :null_session
41
46
  # end
42
47
  #
43
- # It is generally safe to exclude XHR requests from CSRF protection
44
- # (like the code snippet above does), because XHR requests can only be made from
45
- # the same origin. Note however that any cross-origin third party domain
46
- # allowed via {CORS}[https://en.wikipedia.org/wiki/Cross-origin_resource_sharing]
47
- # will also be able to create XHR requests. Be sure to check your
48
- # CORS configuration before disabling forgery protection for XHR.
49
- #
50
- # CSRF protection is turned on with the <tt>protect_from_forgery</tt> method.
51
- # By default <tt>protect_from_forgery</tt> protects your session with
52
- # <tt>:null_session</tt> method, which provides an empty session
53
- # during request.
54
- #
55
- # We may want to disable CSRF protection for APIs since they are typically
56
- # designed to be state-less. That is, the request API client will handle
57
- # the session for you instead of Rails.
48
+ # Note that API only applications don't include this module or a session middleware
49
+ # by default, and so don't require CSRF protection to be configured.
58
50
  #
59
51
  # The token parameter is named <tt>authenticity_token</tt> by default. The name and
60
52
  # value of this token must be added to every layout that renders forms by including
@@ -98,6 +90,10 @@ module ActionController #:nodoc:
98
90
  config_accessor :default_protect_from_forgery
99
91
  self.default_protect_from_forgery = false
100
92
 
93
+ # Controls whether URL-safe CSRF tokens are generated.
94
+ config_accessor :urlsafe_csrf_tokens, instance_writer: false
95
+ self.urlsafe_csrf_tokens = false
96
+
101
97
  helper_method :form_authenticity_token
102
98
  helper_method :protect_against_forgery?
103
99
  end
@@ -337,7 +333,7 @@ module ActionController #:nodoc:
337
333
  end
338
334
 
339
335
  begin
340
- masked_token = Base64.strict_decode64(encoded_masked_token)
336
+ masked_token = decode_csrf_token(encoded_masked_token)
341
337
  rescue ArgumentError # encoded_masked_token is invalid Base64
342
338
  return false
343
339
  end
@@ -375,7 +371,7 @@ module ActionController #:nodoc:
375
371
  one_time_pad = SecureRandom.random_bytes(AUTHENTICITY_TOKEN_LENGTH)
376
372
  encrypted_csrf_token = xor_byte_strings(one_time_pad, raw_token)
377
373
  masked_token = one_time_pad + encrypted_csrf_token
378
- Base64.strict_encode64(masked_token)
374
+ encode_csrf_token(masked_token)
379
375
  end
380
376
 
381
377
  def compare_with_real_token(token, session) # :doc:
@@ -401,8 +397,8 @@ module ActionController #:nodoc:
401
397
  end
402
398
 
403
399
  def real_csrf_token(session) # :doc:
404
- session[:_csrf_token] ||= SecureRandom.base64(AUTHENTICITY_TOKEN_LENGTH)
405
- Base64.strict_decode64(session[:_csrf_token])
400
+ session[:_csrf_token] ||= generate_csrf_token
401
+ decode_csrf_token(session[:_csrf_token])
406
402
  end
407
403
 
408
404
  def per_form_csrf_token(session, action_path, method) # :doc:
@@ -470,5 +466,33 @@ module ActionController #:nodoc:
470
466
  uri = URI.parse(action_path)
471
467
  uri.path.chomp("/")
472
468
  end
469
+
470
+ def generate_csrf_token # :nodoc:
471
+ if urlsafe_csrf_tokens
472
+ SecureRandom.urlsafe_base64(AUTHENTICITY_TOKEN_LENGTH, padding: false)
473
+ else
474
+ SecureRandom.base64(AUTHENTICITY_TOKEN_LENGTH)
475
+ end
476
+ end
477
+
478
+ def encode_csrf_token(csrf_token) # :nodoc:
479
+ if urlsafe_csrf_tokens
480
+ Base64.urlsafe_encode64(csrf_token, padding: false)
481
+ else
482
+ Base64.strict_encode64(csrf_token)
483
+ end
484
+ end
485
+
486
+ def decode_csrf_token(encoded_csrf_token) # :nodoc:
487
+ if urlsafe_csrf_tokens
488
+ Base64.urlsafe_decode64(encoded_csrf_token)
489
+ else
490
+ begin
491
+ Base64.strict_decode64(encoded_csrf_token)
492
+ rescue ArgumentError
493
+ Base64.urlsafe_decode64(encoded_csrf_token)
494
+ end
495
+ end
496
+ end
473
497
  end
474
498
  end
@@ -14,13 +14,13 @@ module ActionDispatch
14
14
  @filename = filename
15
15
  end
16
16
 
17
- TRADITIONAL_ESCAPED_CHAR = /[^ A-Za-z0-9!#$+.^_`|~-]/
17
+ TRADITIONAL_ESCAPED_CHAR = /[^ A-Za-z0-9!\#$+.^_`|~-]/
18
18
 
19
19
  def ascii_filename
20
20
  'filename="' + percent_escape(I18n.transliterate(filename), TRADITIONAL_ESCAPED_CHAR) + '"'
21
21
  end
22
22
 
23
- RFC_5987_ESCAPED_CHAR = /[^A-Za-z0-9!#$&+.^_`|~-]/
23
+ RFC_5987_ESCAPED_CHAR = /[^A-Za-z0-9!\#$&+.^_`|~-]/
24
24
 
25
25
  def utf8_filename
26
26
  "filename*=UTF-8''" + percent_escape(filename, RFC_5987_ESCAPED_CHAR)
@@ -7,6 +7,8 @@ module ActionDispatch
7
7
  module MimeNegotiation
8
8
  extend ActiveSupport::Concern
9
9
 
10
+ class InvalidType < ::Mime::Type::InvalidMimeType; end
11
+
10
12
  RESCUABLE_MIME_FORMAT_ERRORS = [
11
13
  ActionController::BadRequest,
12
14
  ActionDispatch::Http::Parameters::ParseError,
@@ -25,6 +27,8 @@ module ActionDispatch
25
27
  nil
26
28
  end
27
29
  set_header k, v
30
+ rescue ::Mime::Type::InvalidMimeType => e
31
+ raise InvalidType, e.message
28
32
  end
29
33
  end
30
34
 
@@ -47,6 +51,8 @@ module ActionDispatch
47
51
  Mime::Type.parse(header)
48
52
  end
49
53
  set_header k, v
54
+ rescue ::Mime::Type::InvalidMimeType => e
55
+ raise InvalidType, e.message
50
56
  end
51
57
  end
52
58
 
@@ -89,7 +89,7 @@ module ActionDispatch
89
89
  return params unless controller && controller.valid_encoding?
90
90
 
91
91
  if binary_params_for?(controller, action)
92
- ActionDispatch::Request::Utils.each_param_value(params) do |param|
92
+ ActionDispatch::Request::Utils.each_param_value(params.except(:controller, :action)) do |param|
93
93
  param.force_encoding ::Encoding::ASCII_8BIT
94
94
  end
95
95
  end
@@ -133,6 +133,8 @@ module ActionDispatch
133
133
  HTTP_METHOD_LOOKUP[method] = method.underscore.to_sym
134
134
  }
135
135
 
136
+ alias raw_request_method request_method # :nodoc:
137
+
136
138
  # Returns the HTTP \method that the application should see.
137
139
  # In the case where the \method was overridden by a middleware
138
140
  # (for instance, if a HEAD request was converted to a GET,
@@ -33,7 +33,7 @@ module ActionDispatch
33
33
  if uri.relative? || uri.scheme == "http" || uri.scheme == "https"
34
34
  body = "<html><body>You are being <a href=\"#{ERB::Util.unwrapped_html_escape(location)}\">redirected</a>.</body></html>"
35
35
  else
36
- return [400, {"Content-Type" => "text/plain"}, ["Invalid redirection URI"]]
36
+ return [400, { "Content-Type" => "text/plain" }, ["Invalid redirection URI"]]
37
37
  end
38
38
 
39
39
  [302, {
@@ -458,7 +458,13 @@ module ActionDispatch
458
458
 
459
459
  def [](name)
460
460
  if data = @parent_jar[name.to_s]
461
- parse(name, data, purpose: "cookie.#{name}") || parse(name, data)
461
+ result = parse(name, data, purpose: "cookie.#{name}")
462
+
463
+ if result.nil?
464
+ parse(name, data)
465
+ else
466
+ result
467
+ end
462
468
  end
463
469
  end
464
470
 
@@ -63,8 +63,8 @@ module ActionDispatch
63
63
  if request.get_header("action_dispatch.show_detailed_exceptions")
64
64
  begin
65
65
  content_type = request.formats.first
66
- rescue Mime::Type::InvalidMimeType
67
- render_for_api_request(Mime[:text], wrapper)
66
+ rescue ActionDispatch::Http::MimeNegotiation::InvalidType
67
+ content_type = Mime[:text]
68
68
  end
69
69
 
70
70
  if api_request?(content_type)
@@ -12,7 +12,7 @@ module ActionDispatch
12
12
  "ActionController::UnknownHttpMethod" => :method_not_allowed,
13
13
  "ActionController::NotImplemented" => :not_implemented,
14
14
  "ActionController::UnknownFormat" => :not_acceptable,
15
- "Mime::Type::InvalidMimeType" => :not_acceptable,
15
+ "ActionDispatch::Http::MimeNegotiation::InvalidType" => :not_acceptable,
16
16
  "ActionController::MissingExactTemplate" => :not_acceptable,
17
17
  "ActionController::InvalidAuthenticityToken" => :unprocessable_entity,
18
18
  "ActionController::InvalidCrossOriginRequest" => :unprocessable_entity,
@@ -46,9 +46,9 @@ module ActionDispatch
46
46
 
47
47
  def sanitize_string(host)
48
48
  if host.start_with?(".")
49
- /\A(.+\.)?#{Regexp.escape(host[1..-1])}\z/
49
+ /\A(.+\.)?#{Regexp.escape(host[1..-1])}\z/i
50
50
  else
51
- host
51
+ /\A#{Regexp.escape host}\z/i
52
52
  end
53
53
  end
54
54
  end
@@ -86,21 +86,15 @@ module ActionDispatch
86
86
  end
87
87
 
88
88
  private
89
+ HOSTNAME = /[a-z0-9.-]+|\[[a-f0-9]*:[a-f0-9.:]+\]/i
90
+ VALID_ORIGIN_HOST = /\A(#{HOSTNAME})(?::\d+)?\z/
91
+ VALID_FORWARDED_HOST = /(?:\A|,[ ]?)(#{HOSTNAME})(?::\d+)?\z/
92
+
89
93
  def authorized?(request)
90
- valid_host = /
91
- \A
92
- (?<host>[a-z0-9.-]+|\[[a-f0-9]*:[a-f0-9\.:]+\])
93
- (:\d+)?
94
- \z
95
- /x
96
-
97
- origin_host = valid_host.match(
98
- request.get_header("HTTP_HOST").to_s.downcase)
99
- forwarded_host = valid_host.match(
100
- request.x_forwarded_host.to_s.split(/,\s?/).last)
101
-
102
- origin_host && @permissions.allows?(origin_host[:host]) && (
103
- forwarded_host.nil? || @permissions.allows?(forwarded_host[:host]))
94
+ origin_host = request.get_header("HTTP_HOST")&.slice(VALID_ORIGIN_HOST, 1) || ""
95
+ forwarded_host = request.x_forwarded_host&.slice(VALID_FORWARDED_HOST, 1) || ""
96
+
97
+ @permissions.allows?(origin_host) && (forwarded_host.blank? || @permissions.allows?(forwarded_host))
104
98
  end
105
99
 
106
100
  def mark_as_authorized(request)
@@ -23,7 +23,7 @@ module ActionDispatch
23
23
  status = request.path_info[1..-1].to_i
24
24
  begin
25
25
  content_type = request.formats.first
26
- rescue Mime::Type::InvalidMimeType
26
+ rescue ActionDispatch::Http::MimeNegotiation::InvalidType
27
27
  content_type = Mime[:text]
28
28
  end
29
29
  body = { status: status, error: Rack::Utils::HTTP_STATUS_CODES.fetch(status, Rack::Utils::HTTP_STATUS_CODES[500]) }
@@ -6,6 +6,7 @@
6
6
  <%= @exception.message %>
7
7
  <% if defined?(ActiveStorage) && @exception.message.match?(%r{#{ActiveStorage::Blob.table_name}|#{ActiveStorage::Attachment.table_name}}) %>
8
8
  To resolve this issue run: rails active_storage:install
9
+ <% end %>
9
10
  <% if defined?(ActionMailbox) && @exception.message.match?(%r{#{ActionMailbox::InboundEmail.table_name}}) %>
10
11
  To resolve this issue run: rails action_mailbox:install
11
12
  <% end %>
@@ -107,6 +107,7 @@ module ActionDispatch
107
107
  @_routes = nil
108
108
  super
109
109
  end
110
+ ruby2_keywords(:initialize) if respond_to?(:ruby2_keywords, true)
110
111
 
111
112
  # Hook overridden in controller to add request information
112
113
  # with +default_url_options+. Application logic should not
@@ -64,14 +64,14 @@ module ActionDispatch
64
64
 
65
65
  private
66
66
  def headless_chrome_browser_options
67
- capabilities.args << "--headless"
68
- capabilities.args << "--disable-gpu" if Gem.win_platform?
67
+ capabilities.add_argument("--headless")
68
+ capabilities.add_argument("--disable-gpu") if Gem.win_platform?
69
69
 
70
70
  capabilities
71
71
  end
72
72
 
73
73
  def headless_firefox_browser_options
74
- capabilities.args << "-headless"
74
+ capabilities.add_argument("-headless")
75
75
 
76
76
  capabilities
77
77
  end
@@ -9,8 +9,8 @@ module ActionPack
9
9
  module VERSION
10
10
  MAJOR = 6
11
11
  MINOR = 0
12
- TINY = 3
13
- PRE = "7"
12
+ TINY = 4
13
+ PRE = "1"
14
14
 
15
15
  STRING = [MAJOR, MINOR, TINY, PRE].compact.join(".")
16
16
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: actionpack
3
3
  version: !ruby/object:Gem::Version
4
- version: 6.0.3.7
4
+ version: 6.0.4.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - David Heinemeier Hansson
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-05-05 00:00:00.000000000 Z
11
+ date: 2021-08-19 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -16,14 +16,14 @@ dependencies:
16
16
  requirements:
17
17
  - - '='
18
18
  - !ruby/object:Gem::Version
19
- version: 6.0.3.7
19
+ version: 6.0.4.1
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - '='
25
25
  - !ruby/object:Gem::Version
26
- version: 6.0.3.7
26
+ version: 6.0.4.1
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: rack
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -98,28 +98,28 @@ dependencies:
98
98
  requirements:
99
99
  - - '='
100
100
  - !ruby/object:Gem::Version
101
- version: 6.0.3.7
101
+ version: 6.0.4.1
102
102
  type: :runtime
103
103
  prerelease: false
104
104
  version_requirements: !ruby/object:Gem::Requirement
105
105
  requirements:
106
106
  - - '='
107
107
  - !ruby/object:Gem::Version
108
- version: 6.0.3.7
108
+ version: 6.0.4.1
109
109
  - !ruby/object:Gem::Dependency
110
110
  name: activemodel
111
111
  requirement: !ruby/object:Gem::Requirement
112
112
  requirements:
113
113
  - - '='
114
114
  - !ruby/object:Gem::Version
115
- version: 6.0.3.7
115
+ version: 6.0.4.1
116
116
  type: :development
117
117
  prerelease: false
118
118
  version_requirements: !ruby/object:Gem::Requirement
119
119
  requirements:
120
120
  - - '='
121
121
  - !ruby/object:Gem::Version
122
- version: 6.0.3.7
122
+ version: 6.0.4.1
123
123
  description: Web apps on Rails. Simple, battle-tested conventions for building and
124
124
  testing MVC web applications. Works with any Rack-compatible server.
125
125
  email: david@loudthinking.com
@@ -310,10 +310,10 @@ licenses:
310
310
  - MIT
311
311
  metadata:
312
312
  bug_tracker_uri: https://github.com/rails/rails/issues
313
- changelog_uri: https://github.com/rails/rails/blob/v6.0.3.7/actionpack/CHANGELOG.md
314
- documentation_uri: https://api.rubyonrails.org/v6.0.3.7/
313
+ changelog_uri: https://github.com/rails/rails/blob/v6.0.4.1/actionpack/CHANGELOG.md
314
+ documentation_uri: https://api.rubyonrails.org/v6.0.4.1/
315
315
  mailing_list_uri: https://discuss.rubyonrails.org/c/rubyonrails-talk
316
- source_code_uri: https://github.com/rails/rails/tree/v6.0.3.7/actionpack
316
+ source_code_uri: https://github.com/rails/rails/tree/v6.0.4.1/actionpack
317
317
  post_install_message:
318
318
  rdoc_options: []
319
319
  require_paths:
@@ -330,7 +330,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
330
330
  version: '0'
331
331
  requirements:
332
332
  - none
333
- rubygems_version: 3.1.2
333
+ rubygems_version: 3.2.15
334
334
  signing_key:
335
335
  specification_version: 4
336
336
  summary: Web-flow and rendering framework putting the VC in MVC (part of Rails).