-
Notifications
You must be signed in to change notification settings - Fork 21.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Default Message Encryptor Cipher to AES-256-GCM From AES-256-CBC #29263
Conversation
Gemfile.lock
Outdated
@@ -433,4 +433,4 @@ DEPENDENCIES | |||
websocket-client-simple! | |||
|
|||
BUNDLED WITH | |||
1.14.6 | |||
1.15.0 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please remove these Gemfile.lock changes. See Eileen's contributing to Rails workshop around amending and rebasing for some help on how: https://youtu.be/7zoD6NZy6vY?t=1h25s
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you for the feedback @kaspth, I'll fix it and add another commit 👍
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Don't add another commit. Just rebase/amend this one :)
For some reason Travis didn't run your pull request. Try the rebase/amend then force push. |
@@ -119,7 +119,7 @@ def assert_not_decrypted(value) | |||
end | |||
|
|||
def assert_not_verified(value) | |||
assert_raise(ActiveSupport::MessageVerifier::InvalidSignature) do | |||
assert_raise(ActiveSupport::MessageEncryptor::InvalidMessage) do |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why is this change needed?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Previously the setup method used aes-256-cbc cipher while writing this test and had made use of Message Verifier. However, after playing around with the tests, I realized this test was failing because ActiveSupport::MessageVerifier::InvalidSignature was raised by message verifier, and the new default cipher - aes-256-gcm used NullVerifier.
Okay, now we'll need a similar setting to what the AEAD cookies has here: https://github.com/rails/rails/pull/28132/files#diff-7f4141d796a8aad409136b2b6dc774b0R15 E.g. that there's a new 5.2 config to default the encryptor to gcm: # Other configs in new_framework_defaults_5_2.rb…
# Default encrypted messages to use AES-256-GCM encryption.
# Rails.application.active_support.message_encryptor.use_authenticated_encryption = true Then auto default that to true in If we don't have that config, we break backwardscompatibility — that's what the test failures show. |
@@ -13,3 +13,6 @@ | |||
# Use AES 256 GCM authenticated encryption for encrypted cookies. | |||
# Existing cookies will be converted on read then written with the new scheme. | |||
# Rails.application.config.action_dispatch.use_authenticated_cookie_encryption = true | |||
|
|||
# Use AES 256 GCM authenticated encryption as default for encrypting messages. | |||
# Rails.application.config.active_support.message_encryptor.use_authenticated_cookie_encryption = true |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shouldn't say use_authenticated_cookie_encryption
but just use_authenticated_encryption
😊
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I had corrected that mistake, don't know how it crept in again. Apologies! :)
@@ -13,3 +13,6 @@ | |||
# Use AES 256 GCM authenticated encryption for encrypted cookies. | |||
# Existing cookies will be converted on read then written with the new scheme. | |||
# Rails.application.config.action_dispatch.use_authenticated_cookie_encryption = true |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ideally, we should be able to remove this config and use the below one to infer it. But that's for another time.
cc @mikeycgto
# bits. If you are using a user-entered secret, you can generate a suitable | ||
# key by using <tt>ActiveSupport::KeyGenerator</tt> or a similar key | ||
# derivation function. | ||
# derivation function |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Keep the period.
@@ -66,7 +77,7 @@ def initialize(secret, *signature_key_or_options) | |||
sign_secret = signature_key_or_options.first | |||
@secret = secret | |||
@sign_secret = sign_secret | |||
@cipher = options[:cipher] || DEFAULT_CIPHER | |||
@cipher = options[:cipher] || MessageEncryptor.default_cipher |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
self.class.default_cipher
@@ -19,7 +19,18 @@ module ActiveSupport | |||
# encrypted_data = crypt.encrypt_and_sign('my secret data') # => "NlFBTTMwOUV5UlA1QlNEN2xkY2d6eThYWWh..." | |||
# crypt.decrypt_and_verify(encrypted_data) # => "my secret data" | |||
class MessageEncryptor | |||
DEFAULT_CIPHER = "aes-256-cbc" | |||
class << self | |||
#use_authenticated_message_encryption is used to activate 'aes-256-gcm' as default cipher |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This comment doesn't really add anything to me. Let's just document it elsewhere.
@@ -13,3 +13,6 @@ | |||
# Use AES 256 GCM authenticated encryption for encrypted cookies. | |||
# Existing cookies will be converted on read then written with the new scheme. | |||
# Rails.application.config.action_dispatch.use_authenticated_cookie_encryption = true | |||
|
|||
# Use AES 256 GCM authenticated encryption as default for encrypting messages. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
as default for
-> when
ActiveSupport::MessageEncryptor.use_authenticated_message_encryption = true | ||
else | ||
ActiveSupport::MessageEncryptor.use_authenticated_message_encryption = false | ||
end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This all needs to be wrapped in an initializer
(with a descriptive name) so it's run when the app boots and not when this file is parsed.
This Railtie subclass is marked as # :nodoc
meaning it won't show up in documentation, so just skip the comments here.
I'd rewrite to this within the initializer
:
if config.active_support.respond_to?(:use_authenticated_message_encryption)
ActiveSupport::MessageEncryptor.use_authenticated_message_encryption =
config.active_support.use_authenticated_message_encryption
end
We have to use respond_to?
because config.active_support
, an instance of ActiveSupport::OrderedOptions
, raises if the key is unassigned.
Woah, hey you got the tests to pass! 👏 — make sure you look at Code Climate too, there's one thing missing there. 😊 Now we just need to test that the default change works. Let's just go with setting Also: |
@@ -7,6 +7,13 @@ class Railtie < Rails::Railtie # :nodoc: | |||
|
|||
config.eager_load_namespaces << ActiveSupport | |||
|
|||
initializer "active_support.set_authenticated_message_encryption_as_default" do |app| |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@kaspth
Whenever, I make this change, Travis CI fails, because of sessions_test.rb which outputs:
- Failure:
ApplicationTests::MiddlewareSessionTest#test_session_upgrading_from_AES-CBC-HMAC_encryption_to_AES-GCM_encryption [test/application/middleware/session_test.rb:351]:
Expected: "1"
Actual: ""
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yep, see the other comment about why 😊
Let's just clip "_as_default" from the initializer title while we're here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So close now!
@@ -339,6 +339,9 @@ def read_raw_cookie | |||
|
|||
# Enable AEAD cookies | |||
config.action_dispatch.use_authenticated_cookie_encryption = true | |||
|
|||
# Enable Authenticated Message Encryption. | |||
config.active_support.use_authenticated_message_encryption = true |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This will be true by default, so there's no need to set this.
We should assign the cbc cipher:
to the legacy encryptor in cookies middleware. Then the test passes.
@@ -7,6 +7,13 @@ class Railtie < Rails::Railtie # :nodoc: | |||
|
|||
config.eager_load_namespaces << ActiveSupport | |||
|
|||
initializer "active_support.set_authenticated_message_encryption_as_default" do |app| |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yep, see the other comment about why 😊
Let's just clip "_as_default" from the initializer title while we're here.
class << self | ||
attr_accessor :use_authenticated_message_encryption | ||
|
||
def default_cipher |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Needs a # :nodoc
same for the use_authenticated_message_encryption
accessor.
@@ -290,7 +290,7 @@ def read_raw_cookie | |||
get "/foo/read_encrypted_cookie" | |||
assert_equal "2", last_response.body | |||
|
|||
cipher = "aes-256-gcm" | |||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This shouldn't be changed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oops! My bad!
@@ -339,7 +339,8 @@ def read_raw_cookie | |||
|
|||
# Enable AEAD cookies | |||
config.action_dispatch.use_authenticated_cookie_encryption = true | |||
RUBY | |||
|
|||
RUBY |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This neither.
@@ -630,7 +630,7 @@ def initialize(parent_jar) | |||
secret = key_generator.generate_key(request.encrypted_cookie_salt || "")[0, ActiveSupport::MessageEncryptor.key_len] | |||
sign_secret = key_generator.generate_key(request.encrypted_signed_cookie_salt || "") | |||
|
|||
@legacy_encryptor = ActiveSupport::MessageEncryptor.new(secret, sign_secret, digest: digest, serializer: ActiveSupport::MessageEncryptor::NullSerializer) | |||
@legacy_encryptor = ActiveSupport::MessageEncryptor.new(secret, sign_secret, cipher: 'aes-256-cbc', digest: digest, serializer: ActiveSupport::MessageEncryptor::NullSerializer) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use double quoted strings.
- Introduce a method to select default cipher, and maintain backward compatibility
@kaspth
Currently ActiveSupport::MessageEncryptor defaults to CBC encryption, but it could stand to benefit from defaulting to
aes-256-gcm
encryption for the same reasons as cookies.