diff options
Diffstat (limited to 'actionpack')
-rw-r--r-- | actionpack/CHANGELOG.md | 6 | ||||
-rw-r--r-- | actionpack/lib/action_dispatch/middleware/cookies.rb | 24 | ||||
-rw-r--r-- | actionpack/test/dispatch/cookies_test.rb | 65 |
3 files changed, 24 insertions, 71 deletions
diff --git a/actionpack/CHANGELOG.md b/actionpack/CHANGELOG.md index 1d4b27a0f9..16090e7946 100644 --- a/actionpack/CHANGELOG.md +++ b/actionpack/CHANGELOG.md @@ -7,14 +7,14 @@ *Michael J Coyne* -* Use Capybara registered `:puma` server config. +* Use Capybara registered `:puma` server config. The Capybara registered `:puma` server ensures the puma server is run in process so connection sharing and open request detection work correctly by default. *Thomas Walpole* -* Cookies `:expires` option supports `ActiveSupport::Duration` object. +* Cookies `:expires` option supports `ActiveSupport::Duration` object. cookies[:user_name] = { value: "assain", expires: 1.hour } cookies[:key] = { value: "a yummy cookie", expires: 6.months } @@ -23,7 +23,7 @@ *Assain Jaleel* -* Enforce signed/encrypted cookie expiry server side. +* Enforce signed/encrypted cookie expiry server side. Rails can thwart attacks by malicious clients that don't honor a cookie's expiry. diff --git a/actionpack/lib/action_dispatch/middleware/cookies.rb b/actionpack/lib/action_dispatch/middleware/cookies.rb index b3831649a8..0213987c99 100644 --- a/actionpack/lib/action_dispatch/middleware/cookies.rb +++ b/actionpack/lib/action_dispatch/middleware/cookies.rb @@ -264,9 +264,9 @@ module ActionDispatch end def upgrade_legacy_hmac_aes_cbc_cookies? - request.secret_key_base.present? && - request.encrypted_signed_cookie_salt.present? && - request.encrypted_cookie_salt.present? && + request.secret_key_base.present? && + request.encrypted_signed_cookie_salt.present? && + request.encrypted_cookie_salt.present? && request.use_authenticated_cookie_encryption end @@ -570,12 +570,12 @@ module ActionDispatch secret = request.key_generator.generate_key(request.signed_cookie_salt) @verifier = ActiveSupport::MessageVerifier.new(secret, digest: signed_cookie_digest, serializer: SERIALIZER) - request.cookies_rotations.signed.each do |rotation_options| - @verifier.rotate serializer: SERIALIZER, **rotation_options + request.cookies_rotations.signed.each do |*secrets, **options| + @verifier.rotate(*secrets, serializer: SERIALIZER, **options) end if upgrade_legacy_signed_cookies? - @verifier.rotate raw_key: request.secret_token, serializer: SERIALIZER + @verifier.rotate request.secret_token, serializer: SERIALIZER end end @@ -603,14 +603,16 @@ module ActionDispatch secret = request.key_generator.generate_key(request.authenticated_encrypted_cookie_salt, key_len) @encryptor = ActiveSupport::MessageEncryptor.new(secret, cipher: encrypted_cookie_cipher, serializer: SERIALIZER) - request.cookies_rotations.encrypted.each do |rotation_options| - @encryptor.rotate serializer: SERIALIZER, **rotation_options + request.cookies_rotations.encrypted.each do |*secrets, **options| + @encryptor.rotate(*secrets, serializer: SERIALIZER, **options) end if upgrade_legacy_hmac_aes_cbc_cookies? - @encryptor.rotate \ - key_generator: request.key_generator, salt: request.encrypted_cookie_salt, signed_salt: request.encrypted_signed_cookie_salt, - cipher: "aes-256-cbc", digest: digest, serializer: SERIALIZER + legacy_cipher = "aes-256-cbc" + secret = request.key_generator.generate_key(request.encrypted_cookie_salt, ActiveSupport::MessageEncryptor.key_len(legacy_cipher)) + sign_secret = request.key_generator.generate_key(request.encrypted_signed_cookie_salt) + + @encryptor.rotate(secret, sign_secret, cipher: legacy_cipher, digest: digest, serializer: SERIALIZER) end if upgrade_legacy_signed_cookies? diff --git a/actionpack/test/dispatch/cookies_test.rb b/actionpack/test/dispatch/cookies_test.rb index 706d0be9c2..70587fa2b0 100644 --- a/actionpack/test/dispatch/cookies_test.rb +++ b/actionpack/test/dispatch/cookies_test.rb @@ -461,37 +461,13 @@ class CookiesTest < ActionController::TestCase assert_equal verifier.generate(45), cookies[:user_id] end - def test_signed_cookie_rotations_with_secret_key_base_and_digest - rotated_secret_key_base = "b3c631c314c0bbca50c1b2843150fe33" - rotated_salt = "signed cookie" + def test_signed_cookie_rotating_secret_and_digest + secret = "b3c631c314c0bbca50c1b2843150fe33" @request.env["action_dispatch.signed_cookie_digest"] = "SHA256" - @request.env["action_dispatch.cookies_rotations"].rotate :signed, - secret: rotated_secret_key_base, salt: rotated_salt, digest: "SHA1" - - old_secret = ActiveSupport::KeyGenerator.new(rotated_secret_key_base, iterations: 1000).generate_key(rotated_salt) - old_message = ActiveSupport::MessageVerifier.new(old_secret, digest: "SHA1", serializer: Marshal).generate(45) - - @request.headers["Cookie"] = "user_id=#{old_message}" - - get :get_signed_cookie - assert_equal 45, @controller.send(:cookies).signed[:user_id] - - key_generator = @request.env["action_dispatch.key_generator"] - secret = key_generator.generate_key(@request.env["action_dispatch.signed_cookie_salt"]) - verifier = ActiveSupport::MessageVerifier.new(secret, digest: "SHA256", serializer: Marshal) - assert_equal 45, verifier.verify(@response.cookies["user_id"]) - end - - def test_signed_cookie_rotations_with_raw_key_and_digest - rotated_raw_key = "b3c631c314c0bbca50c1b2843150fe33" - - @request.env["action_dispatch.signed_cookie_digest"] = "SHA256" - @request.env["action_dispatch.cookies_rotations"].rotate :signed, - raw_key: rotated_raw_key, digest: "SHA1" - - old_message = ActiveSupport::MessageVerifier.new(rotated_raw_key, digest: "SHA1", serializer: Marshal).generate(45) + @request.env["action_dispatch.cookies_rotations"].rotate :signed, secret, digest: "SHA1" + old_message = ActiveSupport::MessageVerifier.new(secret, digest: "SHA1", serializer: Marshal).generate(45) @request.headers["Cookie"] = "user_id=#{old_message}" get :get_signed_cookie @@ -993,40 +969,15 @@ class CookiesTest < ActionController::TestCase assert_equal "bar", encryptor.decrypt_and_verify(@response.cookies["foo"]) end - def test_encrypted_cookie_rotations_with_secret_and_salt - rotated_secret_key_base = "b3c631c314c0bbca50c1b2843150fe33" - rotated_salt = "authenticated encrypted cookie" - - @request.env["action_dispatch.encrypted_cookie_cipher"] = "aes-256-gcm" - @request.env["action_dispatch.cookies_rotations"].rotate :encrypted, - secret: rotated_secret_key_base, salt: rotated_salt, cipher: "aes-256-gcm" - - key_len = ActiveSupport::MessageEncryptor.key_len("aes-256-gcm") - - old_secret = ActiveSupport::KeyGenerator.new(rotated_secret_key_base, iterations: 1000).generate_key(rotated_salt, key_len) - old_message = ActiveSupport::MessageEncryptor.new(old_secret, cipher: "aes-256-gcm", serializer: Marshal).encrypt_and_sign("bar") - - @request.headers["Cookie"] = "foo=#{::Rack::Utils.escape old_message}" - - get :get_encrypted_cookie - assert_equal "bar", @controller.send(:cookies).encrypted[:foo] - - key_generator = @request.env["action_dispatch.key_generator"] - secret = key_generator.generate_key(@request.env["action_dispatch.authenticated_encrypted_cookie_salt"], key_len) - encryptor = ActiveSupport::MessageEncryptor.new(secret, cipher: "aes-256-gcm", serializer: Marshal) - assert_equal "bar", encryptor.decrypt_and_verify(@response.cookies["foo"]) - end - - def test_encrypted_cookie_rotations_with_raw_key - raw_key = "b3c631c314c0bbca50c1b2843150fe33" + def test_encrypted_cookie_rotating_secret + secret = "b3c631c314c0bbca50c1b2843150fe33" @request.env["action_dispatch.encrypted_cookie_cipher"] = "aes-256-gcm" - @request.env["action_dispatch.cookies_rotations"].rotate :encrypted, - raw_key: raw_key, cipher: "aes-256-gcm" + @request.env["action_dispatch.cookies_rotations"].rotate :encrypted, secret key_len = ActiveSupport::MessageEncryptor.key_len("aes-256-gcm") - old_message = ActiveSupport::MessageEncryptor.new(raw_key, cipher: "aes-256-gcm", serializer: Marshal).encrypt_and_sign(45) + old_message = ActiveSupport::MessageEncryptor.new(secret, cipher: "aes-256-gcm", serializer: Marshal).encrypt_and_sign(45) @request.headers["Cookie"] = "foo=#{::Rack::Utils.escape old_message}" |