Fixed an issue with migrating legacy json cookies.
Previously, the `VerifyAndUpgradeLegacySignedMessage` assumes all incoming cookies are marshal-encoded. This is not the case when `secret_token` is used in conjunction with the `:json` or `:hybrid` serializer. In those case, when upgrading to use `secret_key_base`, this would cause a `TypeError: incompatible marshal file format` and a 500 error for the user. Fixes #14774. *Godfrey Chan*
This commit is contained in:
parent
650585da8a
commit
2a412b3d6f
@ -1,3 +1,16 @@
|
||||
* Fixed an issue with migrating legacy json cookies.
|
||||
|
||||
Previously, the `VerifyAndUpgradeLegacySignedMessage` assumes all incoming
|
||||
cookies are marshal-encoded. This is not the case when `secret_token` is
|
||||
used in conjunction with the `:json` or `:hybrid` serializer.
|
||||
|
||||
In those case, when upgrading to use `secret_key_base`, this would cause a
|
||||
`TypeError: incompatible marshal file format` and a 500 error for the user.
|
||||
|
||||
Fixes #14774.
|
||||
|
||||
*Godfrey Chan*
|
||||
|
||||
* Make URL escaping more consistent:
|
||||
|
||||
1. Escape '%' characters in URLs - only unescaped data should be passed to URL helpers
|
||||
|
@ -176,11 +176,11 @@ def signed_or_encrypted
|
||||
module VerifyAndUpgradeLegacySignedMessage
|
||||
def initialize(*args)
|
||||
super
|
||||
@legacy_verifier = ActiveSupport::MessageVerifier.new(@options[:secret_token])
|
||||
@legacy_verifier = ActiveSupport::MessageVerifier.new(@options[:secret_token], serializer: NullSerializer)
|
||||
end
|
||||
|
||||
def verify_and_upgrade_legacy_signed_message(name, signed_message)
|
||||
@legacy_verifier.verify(signed_message).tap do |value|
|
||||
deserialize(name, @legacy_verifier.verify(signed_message)).tap do |value|
|
||||
self[name] = { value: value }
|
||||
end
|
||||
rescue ActiveSupport::MessageVerifier::InvalidSignature
|
||||
|
@ -681,6 +681,123 @@ def test_legacy_signed_cookie_is_read_and_transparently_encrypted_by_encrypted_c
|
||||
assert_equal 'bar', encryptor.decrypt_and_verify(@response.cookies["foo"])
|
||||
end
|
||||
|
||||
def test_legacy_json_signed_cookie_is_read_and_transparently_upgraded_by_signed_json_cookie_jar_if_both_secret_token_and_secret_key_base_are_set
|
||||
@request.env["action_dispatch.cookies_serializer"] = :json
|
||||
@request.env["action_dispatch.secret_token"] = "b3c631c314c0bbca50c1b2843150fe33"
|
||||
@request.env["action_dispatch.secret_key_base"] = "c3b95688f35581fad38df788add315ff"
|
||||
|
||||
legacy_value = ActiveSupport::MessageVerifier.new("b3c631c314c0bbca50c1b2843150fe33", serializer: JSON).generate(45)
|
||||
|
||||
@request.headers["Cookie"] = "user_id=#{legacy_value}"
|
||||
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, serializer: JSON)
|
||||
assert_equal 45, verifier.verify(@response.cookies["user_id"])
|
||||
end
|
||||
|
||||
def test_legacy_json_signed_cookie_is_read_and_transparently_encrypted_by_encrypted_json_cookie_jar_if_both_secret_token_and_secret_key_base_are_set
|
||||
@request.env["action_dispatch.cookies_serializer"] = :json
|
||||
@request.env["action_dispatch.secret_token"] = "b3c631c314c0bbca50c1b2843150fe33"
|
||||
@request.env["action_dispatch.secret_key_base"] = "c3b95688f35581fad38df788add315ff"
|
||||
@request.env["action_dispatch.encrypted_cookie_salt"] = "4433796b79d99a7735553e316522acee"
|
||||
@request.env["action_dispatch.encrypted_signed_cookie_salt"] = "00646eb40062e1b1deff205a27cd30f9"
|
||||
|
||||
legacy_value = ActiveSupport::MessageVerifier.new("b3c631c314c0bbca50c1b2843150fe33", serializer: JSON).generate('bar')
|
||||
|
||||
@request.headers["Cookie"] = "foo=#{legacy_value}"
|
||||
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.encrypted_cookie_salt"])
|
||||
sign_secret = key_generator.generate_key(@request.env["action_dispatch.encrypted_signed_cookie_salt"])
|
||||
encryptor = ActiveSupport::MessageEncryptor.new(secret, sign_secret, serializer: JSON)
|
||||
assert_equal 'bar', encryptor.decrypt_and_verify(@response.cookies["foo"])
|
||||
end
|
||||
|
||||
def test_legacy_json_signed_cookie_is_read_and_transparently_upgraded_by_signed_json_hybrid_jar_if_both_secret_token_and_secret_key_base_are_set
|
||||
@request.env["action_dispatch.cookies_serializer"] = :hybrid
|
||||
@request.env["action_dispatch.secret_token"] = "b3c631c314c0bbca50c1b2843150fe33"
|
||||
@request.env["action_dispatch.secret_key_base"] = "c3b95688f35581fad38df788add315ff"
|
||||
|
||||
legacy_value = ActiveSupport::MessageVerifier.new("b3c631c314c0bbca50c1b2843150fe33", serializer: JSON).generate(45)
|
||||
|
||||
@request.headers["Cookie"] = "user_id=#{legacy_value}"
|
||||
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, serializer: JSON)
|
||||
assert_equal 45, verifier.verify(@response.cookies["user_id"])
|
||||
end
|
||||
|
||||
def test_legacy_json_signed_cookie_is_read_and_transparently_encrypted_by_encrypted_hybrid_cookie_jar_if_both_secret_token_and_secret_key_base_are_set
|
||||
@request.env["action_dispatch.cookies_serializer"] = :hybrid
|
||||
@request.env["action_dispatch.secret_token"] = "b3c631c314c0bbca50c1b2843150fe33"
|
||||
@request.env["action_dispatch.secret_key_base"] = "c3b95688f35581fad38df788add315ff"
|
||||
@request.env["action_dispatch.encrypted_cookie_salt"] = "4433796b79d99a7735553e316522acee"
|
||||
@request.env["action_dispatch.encrypted_signed_cookie_salt"] = "00646eb40062e1b1deff205a27cd30f9"
|
||||
|
||||
legacy_value = ActiveSupport::MessageVerifier.new("b3c631c314c0bbca50c1b2843150fe33", serializer: JSON).generate('bar')
|
||||
|
||||
@request.headers["Cookie"] = "foo=#{legacy_value}"
|
||||
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.encrypted_cookie_salt"])
|
||||
sign_secret = key_generator.generate_key(@request.env["action_dispatch.encrypted_signed_cookie_salt"])
|
||||
encryptor = ActiveSupport::MessageEncryptor.new(secret, sign_secret, serializer: JSON)
|
||||
assert_equal 'bar', encryptor.decrypt_and_verify(@response.cookies["foo"])
|
||||
end
|
||||
|
||||
def test_legacy_marshal_signed_cookie_is_read_and_transparently_upgraded_by_signed_json_hybrid_jar_if_both_secret_token_and_secret_key_base_are_set
|
||||
@request.env["action_dispatch.cookies_serializer"] = :hybrid
|
||||
@request.env["action_dispatch.secret_token"] = "b3c631c314c0bbca50c1b2843150fe33"
|
||||
@request.env["action_dispatch.secret_key_base"] = "c3b95688f35581fad38df788add315ff"
|
||||
|
||||
legacy_value = ActiveSupport::MessageVerifier.new("b3c631c314c0bbca50c1b2843150fe33").generate(45)
|
||||
|
||||
@request.headers["Cookie"] = "user_id=#{legacy_value}"
|
||||
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, serializer: JSON)
|
||||
assert_equal 45, verifier.verify(@response.cookies["user_id"])
|
||||
end
|
||||
|
||||
def test_legacy_marshal_signed_cookie_is_read_and_transparently_encrypted_by_encrypted_hybrid_cookie_jar_if_both_secret_token_and_secret_key_base_are_set
|
||||
@request.env["action_dispatch.cookies_serializer"] = :hybrid
|
||||
@request.env["action_dispatch.secret_token"] = "b3c631c314c0bbca50c1b2843150fe33"
|
||||
@request.env["action_dispatch.secret_key_base"] = "c3b95688f35581fad38df788add315ff"
|
||||
@request.env["action_dispatch.encrypted_cookie_salt"] = "4433796b79d99a7735553e316522acee"
|
||||
@request.env["action_dispatch.encrypted_signed_cookie_salt"] = "00646eb40062e1b1deff205a27cd30f9"
|
||||
|
||||
legacy_value = ActiveSupport::MessageVerifier.new("b3c631c314c0bbca50c1b2843150fe33").generate('bar')
|
||||
|
||||
@request.headers["Cookie"] = "foo=#{legacy_value}"
|
||||
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.encrypted_cookie_salt"])
|
||||
sign_secret = key_generator.generate_key(@request.env["action_dispatch.encrypted_signed_cookie_salt"])
|
||||
encryptor = ActiveSupport::MessageEncryptor.new(secret, sign_secret, serializer: JSON)
|
||||
assert_equal 'bar', encryptor.decrypt_and_verify(@response.cookies["foo"])
|
||||
end
|
||||
|
||||
def test_legacy_signed_cookie_is_treated_as_nil_by_signed_cookie_jar_if_tampered
|
||||
@request.env["action_dispatch.secret_token"] = "b3c631c314c0bbca50c1b2843150fe33"
|
||||
@request.env["action_dispatch.secret_key_base"] = "c3b95688f35581fad38df788add315ff"
|
||||
|
Loading…
Reference in New Issue
Block a user