actionpack 5.2.4 → 5.2.4.5
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 +4 -4
- data/CHANGELOG.md +27 -0
- data/lib/action_controller/metal/request_forgery_protection.rb +29 -4
- data/lib/action_controller/metal/strong_parameters.rb +2 -0
- data/lib/action_dispatch.rb +5 -4
- data/lib/action_dispatch/middleware/session/abstract_store.rb +14 -0
- data/lib/action_dispatch/middleware/session/cache_store.rb +11 -6
- data/lib/action_dispatch/middleware/session/cookie_store.rb +17 -7
- data/lib/action_dispatch/request/session.rb +7 -1
- data/lib/action_pack/gem_version.rb +1 -1
- metadata +16 -10
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8458248b602da029b1e9113db9f0305888fdf99bf83ea4fe679ad0ed49b22175
|
4
|
+
data.tar.gz: '085825f1ed9d286aa92cf5fa06fb039534331030d5b70da304c237a492f7ded9'
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7a6b62b3afeeb992a981128fbfab64944e897f20a0e75cbef6fd3d972108321ff440f7344935c8d196c1d1e6d3e08d64f040c6c5aa9ad63f06e9b78875da0c54
|
7
|
+
data.tar.gz: 27a049710288451664d3672a6fb18fe505003d9bb91826408ab507d9de06fa9f1a877a2dfc6b9a9b91e32c0f122cdfd33b1bcd3802e64966e4388c17dcad08e6
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,30 @@
|
|
1
|
+
## Rails 5.2.4.5 (February 10, 2021) ##
|
2
|
+
|
3
|
+
* No changes.
|
4
|
+
|
5
|
+
|
6
|
+
## Rails 5.2.4.4 (September 09, 2020) ##
|
7
|
+
|
8
|
+
* No changes.
|
9
|
+
|
10
|
+
|
11
|
+
## Rails 5.2.4.3 (May 18, 2020) ##
|
12
|
+
|
13
|
+
* [CVE-2020-8166] HMAC raw CSRF token before masking it, so it cannot be used to reconstruct a per-form token
|
14
|
+
|
15
|
+
* [CVE-2020-8164] Return self when calling #each, #each_pair, and #each_value instead of the raw @parameters hash
|
16
|
+
|
17
|
+
|
18
|
+
## Rails 5.2.4.1 (December 18, 2019) ##
|
19
|
+
|
20
|
+
* Fix possible information leak / session hijacking vulnerability.
|
21
|
+
|
22
|
+
The `ActionDispatch::Session::MemcacheStore` is still vulnerable given it requires the
|
23
|
+
gem dalli to be updated as well.
|
24
|
+
|
25
|
+
CVE-2019-16782.
|
26
|
+
|
27
|
+
|
1
28
|
## Rails 5.2.4 (November 27, 2019) ##
|
2
29
|
|
3
30
|
* No changes.
|
@@ -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
|
-
|
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.
|
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
|
-
|
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
|
-
|
424
|
+
identifier
|
400
425
|
)
|
401
426
|
end
|
402
427
|
|
data/lib/action_dispatch.rb
CHANGED
@@ -83,10 +83,11 @@ module ActionDispatch
|
|
83
83
|
end
|
84
84
|
|
85
85
|
module Session
|
86
|
-
autoload :AbstractStore,
|
87
|
-
autoload :
|
88
|
-
autoload :
|
89
|
-
autoload :
|
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 <
|
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 =
|
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(
|
50
|
-
"_session_id:#{
|
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 <
|
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
|
-
|
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.
|
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
|
4
|
+
version: 5.2.4.5
|
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:
|
11
|
+
date: 2021-02-10 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
|
19
|
+
version: 5.2.4.5
|
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
|
26
|
+
version: 5.2.4.5
|
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
|
101
|
+
version: 5.2.4.5
|
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
|
108
|
+
version: 5.2.4.5
|
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
|
115
|
+
version: 5.2.4.5
|
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
|
122
|
+
version: 5.2.4.5
|
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/actionpack
|
297
|
-
changelog_uri: https://github.com/rails/rails/blob/v5.2.4/actionpack/CHANGELOG.md
|
302
|
+
source_code_uri: https://github.com/rails/rails/tree/v5.2.4.5/actionpack
|
303
|
+
changelog_uri: https://github.com/rails/rails/blob/v5.2.4.5/actionpack/CHANGELOG.md
|
298
304
|
post_install_message:
|
299
305
|
rdoc_options: []
|
300
306
|
require_paths:
|