mirror of
https://github.com/rails/rails.git
synced 2022-11-09 12:12:34 -05:00
Start passing cipher from EncryptedCookieJar since we use it to determine key length
This commit is contained in:
parent
ae32b69ab9
commit
79c847892f
4 changed files with 26 additions and 22 deletions
|
@ -372,7 +372,7 @@ module ActionDispatch
|
||||||
|
|
||||||
handle_options(options)
|
handle_options(options)
|
||||||
|
|
||||||
if @cookies[name.to_s] != value or options[:expires]
|
if @cookies[name.to_s] != value || options[:expires]
|
||||||
@cookies[name.to_s] = value
|
@cookies[name.to_s] = value
|
||||||
@set_cookies[name.to_s] = options
|
@set_cookies[name.to_s] = options
|
||||||
@delete_cookies.delete(name.to_s)
|
@delete_cookies.delete(name.to_s)
|
||||||
|
@ -567,19 +567,17 @@ module ActionDispatch
|
||||||
|
|
||||||
class EncryptedCookieJar < AbstractCookieJar # :nodoc:
|
class EncryptedCookieJar < AbstractCookieJar # :nodoc:
|
||||||
include SerializedCookieJars
|
include SerializedCookieJars
|
||||||
DEFAULT_CIPHER = 'aes-256-cbc'
|
|
||||||
|
|
||||||
def initialize(parent_jar, cipher: DEFAULT_CIPHER)
|
def initialize(parent_jar)
|
||||||
super(parent_jar)
|
super
|
||||||
|
|
||||||
if ActiveSupport::LegacyKeyGenerator === key_generator
|
if ActiveSupport::LegacyKeyGenerator === key_generator
|
||||||
raise "You didn't set secrets.secret_key_base, which is required for this cookie jar. " +
|
raise "You didn't set secrets.secret_key_base, which is required for this cookie jar. " +
|
||||||
"Read the upgrade documentation to learn more about this new config option."
|
"Read the upgrade documentation to learn more about this new config option."
|
||||||
end
|
end
|
||||||
|
|
||||||
key_len = OpenSSL::Cipher.new(cipher).key_len
|
secret = key_generator.generate_key(request.encrypted_cookie_salt || "")[0, ActiveSupport::MessageEncryptor.key_len]
|
||||||
secret = key_generator.generate_key(request.encrypted_cookie_salt || '')[0, key_len]
|
sign_secret = key_generator.generate_key(request.encrypted_signed_cookie_salt || "")
|
||||||
sign_secret = key_generator.generate_key(request.encrypted_signed_cookie_salt || '')
|
|
||||||
@encryptor = ActiveSupport::MessageEncryptor.new(secret, sign_secret, digest: digest, serializer: ActiveSupport::MessageEncryptor::NullSerializer)
|
@encryptor = ActiveSupport::MessageEncryptor.new(secret, sign_secret, digest: digest, serializer: ActiveSupport::MessageEncryptor::NullSerializer)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -603,7 +603,7 @@ class CookiesTest < ActionController::TestCase
|
||||||
secret = key_generator.generate_key(encrypted_cookie_salt)
|
secret = key_generator.generate_key(encrypted_cookie_salt)
|
||||||
sign_secret = key_generator.generate_key(encrypted_signed_cookie_salt)
|
sign_secret = key_generator.generate_key(encrypted_signed_cookie_salt)
|
||||||
|
|
||||||
marshal_value = ActiveSupport::MessageEncryptor.new(secret[0..31], sign_secret, serializer: Marshal).encrypt_and_sign("bar")
|
marshal_value = ActiveSupport::MessageEncryptor.new(secret[0, ActiveSupport::MessageEncryptor.key_len], sign_secret, serializer: Marshal).encrypt_and_sign("bar")
|
||||||
@request.headers["Cookie"] = "foo=#{marshal_value}"
|
@request.headers["Cookie"] = "foo=#{marshal_value}"
|
||||||
|
|
||||||
get :get_encrypted_cookie
|
get :get_encrypted_cookie
|
||||||
|
@ -612,7 +612,7 @@ class CookiesTest < ActionController::TestCase
|
||||||
assert_not_equal "bar", cookies[:foo]
|
assert_not_equal "bar", cookies[:foo]
|
||||||
assert_equal "bar", cookies.encrypted[:foo]
|
assert_equal "bar", cookies.encrypted[:foo]
|
||||||
|
|
||||||
encryptor = ActiveSupport::MessageEncryptor.new(secret[0..31], sign_secret, serializer: JSON)
|
encryptor = ActiveSupport::MessageEncryptor.new(secret[0, ActiveSupport::MessageEncryptor.key_len], sign_secret, serializer: JSON)
|
||||||
assert_equal "bar", encryptor.decrypt_and_verify(@response.cookies["foo"])
|
assert_equal "bar", encryptor.decrypt_and_verify(@response.cookies["foo"])
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -624,7 +624,7 @@ class CookiesTest < ActionController::TestCase
|
||||||
encrypted_signed_cookie_salt = @request.env["action_dispatch.encrypted_signed_cookie_salt"]
|
encrypted_signed_cookie_salt = @request.env["action_dispatch.encrypted_signed_cookie_salt"]
|
||||||
secret = key_generator.generate_key(encrypted_cookie_salt)
|
secret = key_generator.generate_key(encrypted_cookie_salt)
|
||||||
sign_secret = key_generator.generate_key(encrypted_signed_cookie_salt)
|
sign_secret = key_generator.generate_key(encrypted_signed_cookie_salt)
|
||||||
json_value = ActiveSupport::MessageEncryptor.new(secret[0..31], sign_secret, serializer: JSON).encrypt_and_sign("bar")
|
json_value = ActiveSupport::MessageEncryptor.new(secret[0, ActiveSupport::MessageEncryptor.key_len], sign_secret, serializer: JSON).encrypt_and_sign("bar")
|
||||||
@request.headers["Cookie"] = "foo=#{json_value}"
|
@request.headers["Cookie"] = "foo=#{json_value}"
|
||||||
|
|
||||||
get :get_encrypted_cookie
|
get :get_encrypted_cookie
|
||||||
|
@ -636,10 +636,9 @@ class CookiesTest < ActionController::TestCase
|
||||||
assert_nil @response.cookies["foo"]
|
assert_nil @response.cookies["foo"]
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
def test_compat_encrypted_cookie_using_64_byte_key
|
def test_compat_encrypted_cookie_using_64_byte_key
|
||||||
# Cookie generated with 64 bytes secret
|
# Cookie generated with 64 bytes secret
|
||||||
message = ["566d4e75536d686e633246564e6b493062557079626c566d51574d30515430394c53315665564a694e4563786555744f57537454576b396a5a31566a626e52525054303d2d2d34663234333330623130623261306163363562316266323335396164666364613564643134623131"].pack('H*')
|
message = ["566d4e75536d686e633246564e6b493062557079626c566d51574d30515430394c53315665564a694e4563786555744f57537454576b396a5a31566a626e52525054303d2d2d34663234333330623130623261306163363562316266323335396164666364613564643134623131"].pack("H*")
|
||||||
@request.headers["Cookie"] = "foo=#{message}"
|
@request.headers["Cookie"] = "foo=#{message}"
|
||||||
|
|
||||||
get :get_encrypted_cookie
|
get :get_encrypted_cookie
|
||||||
|
@ -813,8 +812,8 @@ class CookiesTest < ActionController::TestCase
|
||||||
key_generator = @request.env["action_dispatch.key_generator"]
|
key_generator = @request.env["action_dispatch.key_generator"]
|
||||||
secret = key_generator.generate_key(@request.env["action_dispatch.encrypted_cookie_salt"])
|
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"])
|
sign_secret = key_generator.generate_key(@request.env["action_dispatch.encrypted_signed_cookie_salt"])
|
||||||
encryptor = ActiveSupport::MessageEncryptor.new(secret[0..31], sign_secret)
|
encryptor = ActiveSupport::MessageEncryptor.new(secret[0, ActiveSupport::MessageEncryptor.key_len], sign_secret)
|
||||||
assert_equal 'bar', encryptor.decrypt_and_verify(@response.cookies["foo"])
|
assert_equal "bar", encryptor.decrypt_and_verify(@response.cookies["foo"])
|
||||||
end
|
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
|
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
|
||||||
|
@ -852,8 +851,8 @@ class CookiesTest < ActionController::TestCase
|
||||||
key_generator = @request.env["action_dispatch.key_generator"]
|
key_generator = @request.env["action_dispatch.key_generator"]
|
||||||
secret = key_generator.generate_key(@request.env["action_dispatch.encrypted_cookie_salt"])
|
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"])
|
sign_secret = key_generator.generate_key(@request.env["action_dispatch.encrypted_signed_cookie_salt"])
|
||||||
encryptor = ActiveSupport::MessageEncryptor.new(secret[0..31], sign_secret, serializer: JSON)
|
encryptor = ActiveSupport::MessageEncryptor.new(secret[0, ActiveSupport::MessageEncryptor.key_len], sign_secret, serializer: JSON)
|
||||||
assert_equal 'bar', encryptor.decrypt_and_verify(@response.cookies["foo"])
|
assert_equal "bar", encryptor.decrypt_and_verify(@response.cookies["foo"])
|
||||||
end
|
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
|
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
|
||||||
|
@ -891,8 +890,8 @@ class CookiesTest < ActionController::TestCase
|
||||||
key_generator = @request.env["action_dispatch.key_generator"]
|
key_generator = @request.env["action_dispatch.key_generator"]
|
||||||
secret = key_generator.generate_key(@request.env["action_dispatch.encrypted_cookie_salt"])
|
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"])
|
sign_secret = key_generator.generate_key(@request.env["action_dispatch.encrypted_signed_cookie_salt"])
|
||||||
encryptor = ActiveSupport::MessageEncryptor.new(secret[0..31], sign_secret, serializer: JSON)
|
encryptor = ActiveSupport::MessageEncryptor.new(secret[0, ActiveSupport::MessageEncryptor.key_len], sign_secret, serializer: JSON)
|
||||||
assert_equal 'bar', encryptor.decrypt_and_verify(@response.cookies["foo"])
|
assert_equal "bar", encryptor.decrypt_and_verify(@response.cookies["foo"])
|
||||||
end
|
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
|
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
|
||||||
|
@ -930,8 +929,8 @@ class CookiesTest < ActionController::TestCase
|
||||||
key_generator = @request.env["action_dispatch.key_generator"]
|
key_generator = @request.env["action_dispatch.key_generator"]
|
||||||
secret = key_generator.generate_key(@request.env["action_dispatch.encrypted_cookie_salt"])
|
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"])
|
sign_secret = key_generator.generate_key(@request.env["action_dispatch.encrypted_signed_cookie_salt"])
|
||||||
encryptor = ActiveSupport::MessageEncryptor.new(secret[0..31], sign_secret, serializer: JSON)
|
encryptor = ActiveSupport::MessageEncryptor.new(secret[0, ActiveSupport::MessageEncryptor.key_len], sign_secret, serializer: JSON)
|
||||||
assert_equal 'bar', encryptor.decrypt_and_verify(@response.cookies["foo"])
|
assert_equal "bar", encryptor.decrypt_and_verify(@response.cookies["foo"])
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_legacy_signed_cookie_is_treated_as_nil_by_signed_cookie_jar_if_tampered
|
def test_legacy_signed_cookie_is_treated_as_nil_by_signed_cookie_jar_if_tampered
|
||||||
|
|
|
@ -19,6 +19,8 @@ module ActiveSupport
|
||||||
# encrypted_data = crypt.encrypt_and_sign('my secret data') # => "NlFBTTMwOUV5UlA1QlNEN2xkY2d6eThYWWh..."
|
# encrypted_data = crypt.encrypt_and_sign('my secret data') # => "NlFBTTMwOUV5UlA1QlNEN2xkY2d6eThYWWh..."
|
||||||
# crypt.decrypt_and_verify(encrypted_data) # => "my secret data"
|
# crypt.decrypt_and_verify(encrypted_data) # => "my secret data"
|
||||||
class MessageEncryptor
|
class MessageEncryptor
|
||||||
|
DEFAULT_CIPHER = "aes-256-cbc"
|
||||||
|
|
||||||
module NullSerializer #:nodoc:
|
module NullSerializer #:nodoc:
|
||||||
def self.load(value)
|
def self.load(value)
|
||||||
value
|
value
|
||||||
|
@ -77,6 +79,11 @@ module ActiveSupport
|
||||||
_decrypt(verifier.verify(value))
|
_decrypt(verifier.verify(value))
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Given a cipher, returns the key length of the cipher to help generate the key of desired size
|
||||||
|
def self.key_len(cipher = DEFAULT_CIPHER)
|
||||||
|
OpenSSL::Cipher.new(cipher).key_len
|
||||||
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def _encrypt(value)
|
def _encrypt(value)
|
||||||
|
|
|
@ -50,12 +50,12 @@ class MessageEncryptorTest < ActiveSupport::TestCase
|
||||||
|
|
||||||
def test_backwards_compat_for_64_bytes_key
|
def test_backwards_compat_for_64_bytes_key
|
||||||
# 64 bit key
|
# 64 bit key
|
||||||
secret = ["3942b1bf81e622559ed509e3ff274a780784fe9e75b065866bd270438c74da822219de3156473cc27df1fd590e4baf68c95eeb537b6e4d4c5a10f41635b5597e"].pack('H*')
|
secret = ["3942b1bf81e622559ed509e3ff274a780784fe9e75b065866bd270438c74da822219de3156473cc27df1fd590e4baf68c95eeb537b6e4d4c5a10f41635b5597e"].pack("H*")
|
||||||
# Encryptor with 32 bit key, 64 bit secret for verifier
|
# Encryptor with 32 bit key, 64 bit secret for verifier
|
||||||
encryptor = ActiveSupport::MessageEncryptor.new(secret[0..31], secret)
|
encryptor = ActiveSupport::MessageEncryptor.new(secret[0..31], secret)
|
||||||
# Message generated with 64 bit key
|
# Message generated with 64 bit key
|
||||||
message = "eHdGeExnZEwvMSt3U3dKaFl1WFo0TjVvYzA0eGpjbm5WSkt5MXlsNzhpZ0ZnbWhBWFlQZTRwaXE1bVJCS2oxMDZhYVp2dVN3V0lNZUlWQ3c2eVhQbnhnVjFmeVVubmhRKzF3WnZyWHVNMDg9LS1HSisyakJVSFlPb05ISzRMaXRzcFdBPT0=--831a1d54a3cda8a0658dc668a03dedcbce13b5ca"
|
message = "eHdGeExnZEwvMSt3U3dKaFl1WFo0TjVvYzA0eGpjbm5WSkt5MXlsNzhpZ0ZnbWhBWFlQZTRwaXE1bVJCS2oxMDZhYVp2dVN3V0lNZUlWQ3c2eVhQbnhnVjFmeVVubmhRKzF3WnZyWHVNMDg9LS1HSisyakJVSFlPb05ISzRMaXRzcFdBPT0=--831a1d54a3cda8a0658dc668a03dedcbce13b5ca"
|
||||||
assert_equal 'data', encryptor.decrypt_and_verify(message)[:some]
|
assert_equal "data", encryptor.decrypt_and_verify(message)[:some]
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_alternative_serialization_method
|
def test_alternative_serialization_method
|
||||||
|
|
Loading…
Reference in a new issue