actionpack 5.2.4.rc1 → 5.2.4.4

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: 3679931508ff00406357c690c6bc03d08966109a5af4ea64042e0186b0772f96
4
- data.tar.gz: e8da8f7149e84a388350f037eda5cb7729b8edeb778195be79e7f1273d2cc0a6
3
+ metadata.gz: '0581fd2c86192b6ffd29f90a71d0da4aaf9d3040398cb841440102bec565ebf7'
4
+ data.tar.gz: d5957327e6b31e0bb9c0427382ead54bb8a6e8939400a5c3e81c7b2de32cad58
5
5
  SHA512:
6
- metadata.gz: 20695595eef6511baae42535270e30053369304a6629e521afea29f9758eae2b7e7f018e8b263055ba61a88c4a8e543ed1dab320449982c8ff1314b3ae27dcbd
7
- data.tar.gz: 337e059cb93403ba173424a8516cc6c24b393a2cb602e6c8f71cd0db37d6aa7ec8b9a06cd2eb21874eff968adfd0db1dde5e6676783783a3399834ce610fcf98
6
+ metadata.gz: 910806a975bc0a799af4b6cd093a8f1da502d58aaf0903f4ce031b20da8cd16cb803b14ae575ab14cbd65b55a393cc8c0420861cf36547a9d59acde1f03857df
7
+ data.tar.gz: 7a373c8ddedb72c5a7933c85f809b850396c8daba7bdaa34c4447f3d2a8868dc8f508da1899e6b97d7625c5f1723e38b122e09672f95f43ba7db4caa832ddcc3
@@ -1,4 +1,26 @@
1
- ## Rails 5.2.4.rc1 (November 22, 2019) ##
1
+ ## Rails 5.2.4.4 (September 09, 2020) ##
2
+
3
+ * No changes.
4
+
5
+
6
+ ## Rails 5.2.4.3 (May 18, 2020) ##
7
+
8
+ * [CVE-2020-8166] HMAC raw CSRF token before masking it, so it cannot be used to reconstruct a per-form token
9
+
10
+ * [CVE-2020-8164] Return self when calling #each, #each_pair, and #each_value instead of the raw @parameters hash
11
+
12
+
13
+ ## Rails 5.2.4.1 (December 18, 2019) ##
14
+
15
+ * Fix possible information leak / session hijacking vulnerability.
16
+
17
+ The `ActionDispatch::Session::MemcacheStore` is still vulnerable given it requires the
18
+ gem dalli to be updated as well.
19
+
20
+ CVE-2019-16782.
21
+
22
+
23
+ ## Rails 5.2.4 (November 27, 2019) ##
2
24
 
3
25
  * No changes.
4
26
 
@@ -318,13 +318,15 @@ module ActionController #:nodoc:
318
318
  action_path = normalize_action_path(action)
319
319
  per_form_csrf_token(session, action_path, method)
320
320
  else
321
- real_csrf_token(session)
321
+ global_csrf_token(session)
322
322
  end
323
323
 
324
324
  one_time_pad = SecureRandom.random_bytes(AUTHENTICITY_TOKEN_LENGTH)
325
325
  encrypted_csrf_token = xor_byte_strings(one_time_pad, raw_token)
326
326
  masked_token = one_time_pad + encrypted_csrf_token
327
- Base64.strict_encode64(masked_token)
327
+ Base64.urlsafe_encode64(masked_token, padding: false)
328
+
329
+ mask_token(raw_token)
328
330
  end
329
331
 
330
332
  # Checks the client's masked token to see if it matches the
@@ -354,7 +356,8 @@ module ActionController #:nodoc:
354
356
  elsif masked_token.length == AUTHENTICITY_TOKEN_LENGTH * 2
355
357
  csrf_token = unmask_token(masked_token)
356
358
 
357
- compare_with_real_token(csrf_token, session) ||
359
+ compare_with_global_token(csrf_token, session) ||
360
+ compare_with_real_token(csrf_token, session) ||
358
361
  valid_per_form_csrf_token?(csrf_token, session)
359
362
  else
360
363
  false # Token is malformed.
@@ -369,10 +372,21 @@ module ActionController #:nodoc:
369
372
  xor_byte_strings(one_time_pad, encrypted_csrf_token)
370
373
  end
371
374
 
375
+ def mask_token(raw_token) # :doc:
376
+ one_time_pad = SecureRandom.random_bytes(AUTHENTICITY_TOKEN_LENGTH)
377
+ encrypted_csrf_token = xor_byte_strings(one_time_pad, raw_token)
378
+ masked_token = one_time_pad + encrypted_csrf_token
379
+ Base64.strict_encode64(masked_token)
380
+ end
381
+
372
382
  def compare_with_real_token(token, session) # :doc:
373
383
  ActiveSupport::SecurityUtils.fixed_length_secure_compare(token, real_csrf_token(session))
374
384
  end
375
385
 
386
+ def compare_with_global_token(token, session) # :doc:
387
+ ActiveSupport::SecurityUtils.fixed_length_secure_compare(token, global_csrf_token(session))
388
+ end
389
+
376
390
  def valid_per_form_csrf_token?(token, session) # :doc:
377
391
  if per_form_csrf_tokens
378
392
  correct_token = per_form_csrf_token(
@@ -393,10 +407,21 @@ module ActionController #:nodoc:
393
407
  end
394
408
 
395
409
  def per_form_csrf_token(session, action_path, method) # :doc:
410
+ csrf_token_hmac(session, [action_path, method.downcase].join("#"))
411
+ end
412
+
413
+ GLOBAL_CSRF_TOKEN_IDENTIFIER = "!real_csrf_token"
414
+ private_constant :GLOBAL_CSRF_TOKEN_IDENTIFIER
415
+
416
+ def global_csrf_token(session) # :doc:
417
+ csrf_token_hmac(session, GLOBAL_CSRF_TOKEN_IDENTIFIER)
418
+ end
419
+
420
+ def csrf_token_hmac(session, identifier) # :doc:
396
421
  OpenSSL::HMAC.digest(
397
422
  OpenSSL::Digest::SHA256.new,
398
423
  real_csrf_token(session),
399
- [action_path, method.downcase].join("#")
424
+ identifier
400
425
  )
401
426
  end
402
427
 
@@ -337,6 +337,8 @@ module ActionController
337
337
  @parameters.each_pair do |key, value|
338
338
  yield [key, convert_hashes_to_parameters(key, value)]
339
339
  end
340
+
341
+ self
340
342
  end
341
343
  alias_method :each, :each_pair
342
344
 
@@ -83,10 +83,11 @@ module ActionDispatch
83
83
  end
84
84
 
85
85
  module Session
86
- autoload :AbstractStore, "action_dispatch/middleware/session/abstract_store"
87
- autoload :CookieStore, "action_dispatch/middleware/session/cookie_store"
88
- autoload :MemCacheStore, "action_dispatch/middleware/session/mem_cache_store"
89
- autoload :CacheStore, "action_dispatch/middleware/session/cache_store"
86
+ autoload :AbstractStore, "action_dispatch/middleware/session/abstract_store"
87
+ autoload :AbstractSecureStore, "action_dispatch/middleware/session/abstract_store"
88
+ autoload :CookieStore, "action_dispatch/middleware/session/cookie_store"
89
+ autoload :MemCacheStore, "action_dispatch/middleware/session/mem_cache_store"
90
+ autoload :CacheStore, "action_dispatch/middleware/session/cache_store"
90
91
  end
91
92
 
92
93
  mattr_accessor :test_app
@@ -83,7 +83,21 @@ module ActionDispatch
83
83
  include SessionObject
84
84
 
85
85
  private
86
+ def set_cookie(request, session_id, cookie)
87
+ request.cookie_jar[key] = cookie
88
+ end
89
+ end
90
+
91
+ class AbstractSecureStore < Rack::Session::Abstract::PersistedSecure
92
+ include Compatibility
93
+ include StaleSessionCheck
94
+ include SessionObject
95
+
96
+ def generate_sid
97
+ Rack::Session::SessionId.new(super)
98
+ end
86
99
 
100
+ private
87
101
  def set_cookie(request, session_id, cookie)
88
102
  request.cookie_jar[key] = cookie
89
103
  end
@@ -12,7 +12,7 @@ module ActionDispatch
12
12
  # * <tt>cache</tt> - The cache to use. If it is not specified, <tt>Rails.cache</tt> will be used.
13
13
  # * <tt>expire_after</tt> - The length of time a session will be stored before automatically expiring.
14
14
  # By default, the <tt>:expires_in</tt> option of the cache is used.
15
- class CacheStore < AbstractStore
15
+ class CacheStore < AbstractSecureStore
16
16
  def initialize(app, options = {})
17
17
  @cache = options[:cache] || Rails.cache
18
18
  options[:expire_after] ||= @cache.options[:expires_in]
@@ -21,7 +21,7 @@ module ActionDispatch
21
21
 
22
22
  # Get a session from the cache.
23
23
  def find_session(env, sid)
24
- unless sid && (session = @cache.read(cache_key(sid)))
24
+ unless sid && (session = get_session_with_fallback(sid))
25
25
  sid, session = generate_sid, {}
26
26
  end
27
27
  [sid, session]
@@ -29,7 +29,7 @@ module ActionDispatch
29
29
 
30
30
  # Set a session in the cache.
31
31
  def write_session(env, sid, session, options)
32
- key = cache_key(sid)
32
+ key = cache_key(sid.private_id)
33
33
  if session
34
34
  @cache.write(key, session, expires_in: options[:expire_after])
35
35
  else
@@ -40,14 +40,19 @@ module ActionDispatch
40
40
 
41
41
  # Remove a session from the cache.
42
42
  def delete_session(env, sid, options)
43
- @cache.delete(cache_key(sid))
43
+ @cache.delete(cache_key(sid.private_id))
44
+ @cache.delete(cache_key(sid.public_id))
44
45
  generate_sid
45
46
  end
46
47
 
47
48
  private
48
49
  # Turn the session id into a cache key.
49
- def cache_key(sid)
50
- "_session_id:#{sid}"
50
+ def cache_key(id)
51
+ "_session_id:#{id}"
52
+ end
53
+
54
+ def get_session_with_fallback(sid)
55
+ @cache.read(cache_key(sid.private_id)) || @cache.read(cache_key(sid.public_id))
51
56
  end
52
57
  end
53
58
  end
@@ -51,7 +51,16 @@ module ActionDispatch
51
51
  # would set the session cookie to expire automatically 14 days after creation.
52
52
  # Other useful options include <tt>:key</tt>, <tt>:secure</tt> and
53
53
  # <tt>:httponly</tt>.
54
- class CookieStore < AbstractStore
54
+ class CookieStore < AbstractSecureStore
55
+ class SessionId < DelegateClass(Rack::Session::SessionId)
56
+ attr_reader :cookie_value
57
+
58
+ def initialize(session_id, cookie_value = {})
59
+ super(session_id)
60
+ @cookie_value = cookie_value
61
+ end
62
+ end
63
+
55
64
  def initialize(app, options = {})
56
65
  super(app, options.merge!(cookie_only: true))
57
66
  end
@@ -59,7 +68,7 @@ module ActionDispatch
59
68
  def delete_session(req, session_id, options)
60
69
  new_sid = generate_sid unless options[:drop]
61
70
  # Reset hash and Assign the new session id
62
- req.set_header("action_dispatch.request.unsigned_session_cookie", new_sid ? { "session_id" => new_sid } : {})
71
+ req.set_header("action_dispatch.request.unsigned_session_cookie", new_sid ? { "session_id" => new_sid.public_id } : {})
63
72
  new_sid
64
73
  end
65
74
 
@@ -67,7 +76,7 @@ module ActionDispatch
67
76
  stale_session_check! do
68
77
  data = unpacked_cookie_data(req)
69
78
  data = persistent_session_id!(data)
70
- [data["session_id"], data]
79
+ [Rack::Session::SessionId.new(data["session_id"]), data]
71
80
  end
72
81
  end
73
82
 
@@ -75,7 +84,8 @@ module ActionDispatch
75
84
 
76
85
  def extract_session_id(req)
77
86
  stale_session_check! do
78
- unpacked_cookie_data(req)["session_id"]
87
+ sid = unpacked_cookie_data(req)["session_id"]
88
+ sid && Rack::Session::SessionId.new(sid)
79
89
  end
80
90
  end
81
91
 
@@ -93,13 +103,13 @@ module ActionDispatch
93
103
 
94
104
  def persistent_session_id!(data, sid = nil)
95
105
  data ||= {}
96
- data["session_id"] ||= sid || generate_sid
106
+ data["session_id"] ||= sid || generate_sid.public_id
97
107
  data
98
108
  end
99
109
 
100
110
  def write_session(req, sid, session_data, options)
101
- session_data["session_id"] = sid
102
- session_data
111
+ session_data["session_id"] = sid.public_id
112
+ SessionId.new(sid, session_data)
103
113
  end
104
114
 
105
115
  def set_cookie(request, session_id, cookie)
@@ -90,7 +90,13 @@ module ActionDispatch
90
90
  # +nil+ if the given key is not found in the session.
91
91
  def [](key)
92
92
  load_for_read!
93
- @delegate[key.to_s]
93
+ key = key.to_s
94
+
95
+ if key == "session_id"
96
+ id&.public_id
97
+ else
98
+ @delegate[key]
99
+ end
94
100
  end
95
101
 
96
102
  # Returns true if the session has the given key or false.
@@ -10,7 +10,7 @@ module ActionPack
10
10
  MAJOR = 5
11
11
  MINOR = 2
12
12
  TINY = 4
13
- PRE = "rc1"
13
+ PRE = "4"
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: 5.2.4.rc1
4
+ version: 5.2.4.4
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: 2019-11-23 00:00:00.000000000 Z
11
+ date: 2020-09-09 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: 5.2.4.rc1
19
+ version: 5.2.4.4
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: 5.2.4.rc1
26
+ version: 5.2.4.4
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: rack
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -31,6 +31,9 @@ dependencies:
31
31
  - - "~>"
32
32
  - !ruby/object:Gem::Version
33
33
  version: '2.0'
34
+ - - ">="
35
+ - !ruby/object:Gem::Version
36
+ version: 2.0.8
34
37
  type: :runtime
35
38
  prerelease: false
36
39
  version_requirements: !ruby/object:Gem::Requirement
@@ -38,6 +41,9 @@ dependencies:
38
41
  - - "~>"
39
42
  - !ruby/object:Gem::Version
40
43
  version: '2.0'
44
+ - - ">="
45
+ - !ruby/object:Gem::Version
46
+ version: 2.0.8
41
47
  - !ruby/object:Gem::Dependency
42
48
  name: rack-test
43
49
  requirement: !ruby/object:Gem::Requirement
@@ -92,28 +98,28 @@ dependencies:
92
98
  requirements:
93
99
  - - '='
94
100
  - !ruby/object:Gem::Version
95
- version: 5.2.4.rc1
101
+ version: 5.2.4.4
96
102
  type: :runtime
97
103
  prerelease: false
98
104
  version_requirements: !ruby/object:Gem::Requirement
99
105
  requirements:
100
106
  - - '='
101
107
  - !ruby/object:Gem::Version
102
- version: 5.2.4.rc1
108
+ version: 5.2.4.4
103
109
  - !ruby/object:Gem::Dependency
104
110
  name: activemodel
105
111
  requirement: !ruby/object:Gem::Requirement
106
112
  requirements:
107
113
  - - '='
108
114
  - !ruby/object:Gem::Version
109
- version: 5.2.4.rc1
115
+ version: 5.2.4.4
110
116
  type: :development
111
117
  prerelease: false
112
118
  version_requirements: !ruby/object:Gem::Requirement
113
119
  requirements:
114
120
  - - '='
115
121
  - !ruby/object:Gem::Version
116
- version: 5.2.4.rc1
122
+ version: 5.2.4.4
117
123
  description: Web apps on Rails. Simple, battle-tested conventions for building and
118
124
  testing MVC web applications. Works with any Rack-compatible server.
119
125
  email: david@loudthinking.com
@@ -293,8 +299,8 @@ homepage: http://rubyonrails.org
293
299
  licenses:
294
300
  - MIT
295
301
  metadata:
296
- source_code_uri: https://github.com/rails/rails/tree/v5.2.4.rc1/actionpack
297
- changelog_uri: https://github.com/rails/rails/blob/v5.2.4.rc1/actionpack/CHANGELOG.md
302
+ source_code_uri: https://github.com/rails/rails/tree/v5.2.4.4/actionpack
303
+ changelog_uri: https://github.com/rails/rails/blob/v5.2.4.4/actionpack/CHANGELOG.md
298
304
  post_install_message:
299
305
  rdoc_options: []
300
306
  require_paths:
@@ -306,12 +312,12 @@ required_ruby_version: !ruby/object:Gem::Requirement
306
312
  version: 2.2.2
307
313
  required_rubygems_version: !ruby/object:Gem::Requirement
308
314
  requirements:
309
- - - ">"
315
+ - - ">="
310
316
  - !ruby/object:Gem::Version
311
- version: 1.3.1
317
+ version: '0'
312
318
  requirements:
313
319
  - none
314
- rubygems_version: 3.0.3
320
+ rubygems_version: 3.1.2
315
321
  signing_key:
316
322
  specification_version: 4
317
323
  summary: Web-flow and rendering framework putting the VC in MVC (part of Rails).