Revert "Revert "Merge pull request #42843 from buckley-w-david/message-verifier-default-serializer""

This reverts commit fd4e63cc28.
This commit is contained in:
Aaron Patterson 2022-03-01 15:14:43 -08:00
parent fd4e63cc28
commit ea9f0103fd
No known key found for this signature in database
GPG Key ID: 953170BCB4FFAFC6
9 changed files with 399 additions and 40 deletions

View File

@ -42,11 +42,13 @@ class ActiveStorage::DiskController < ActiveStorage::BaseController
end
def decode_verified_key
ActiveStorage.verifier.verified(params[:encoded_key], purpose: :blob_key)
key = ActiveStorage.verifier.verified(params[:encoded_key], purpose: :blob_key)
key&.deep_symbolize_keys
end
def decode_verified_token
ActiveStorage.verifier.verified(params[:encoded_token], purpose: :blob_token)
token = ActiveStorage.verifier.verified(params[:encoded_token], purpose: :blob_token)
token&.deep_symbolize_keys
end
def acceptable_content?(token)

View File

@ -72,7 +72,7 @@ module ActiveSupport
#
# === Alternative serializers
#
# By default MessageVerifier uses Marshal to serialize the message. If you want to use
# By default MessageVerifier uses JSON to serialize the message. If you want to use
# another serialization method, you can set the serializer in the options
# hash upon initialization:
#
@ -115,11 +115,20 @@ module ActiveSupport
SEPARATOR = "--" # :nodoc:
SEPARATOR_LENGTH = SEPARATOR.length # :nodoc:
cattr_accessor :default_message_verifier_serializer, instance_accessor: false, default: :marshal
def initialize(secret, digest: nil, serializer: nil)
raise ArgumentError, "Secret should not be nil." unless secret
@secret = secret
@digest = digest&.to_s || "SHA1"
@serializer = serializer || Marshal
@serializer = serializer ||
if @@default_message_verifier_serializer.equal?(:marshal)
Marshal
elsif @@default_message_verifier_serializer.equal?(:hybrid)
JsonWithMarshalFallback
elsif @@default_message_verifier_serializer.equal?(:json)
JSON
end
end
# Checks if a signed message could have been generated by signing an object

View File

@ -167,6 +167,15 @@ module ActiveSupport
end
end
initializer "active_support.set_default_message_verifier_serializer" do |app|
config.after_initialize do
unless app.config.active_support.default_message_verifier_serializer.nil?
ActiveSupport::MessageVerifier.default_message_verifier_serializer =
app.config.active_support.default_message_verifier_serializer
end
end
end
initializer "active_support.set_marshal_serialization" do |app|
config.after_initialize do
unless app.config.active_support.use_marshal_serialization.nil?

View File

@ -19,7 +19,7 @@ class MessageVerifierTest < ActiveSupport::TestCase
def setup
@verifier = ActiveSupport::MessageVerifier.new("Hey, I'm a secret!")
@data = { some: "data", now: Time.utc(2010) }
@data = { "some" => "data", "now" => Time.utc(2010) }
@secret = SecureRandom.random_bytes(32)
end
@ -70,25 +70,6 @@ class MessageVerifierTest < ActiveSupport::TestCase
ActiveSupport.parse_json_times, Time.zone = previous
end
def test_raise_error_when_argument_class_is_not_loaded
# To generate the valid message below:
#
# AutoloadClass = Struct.new(:foo)
# valid_message = @verifier.generate(foo: AutoloadClass.new('foo'))
#
valid_message = "BAh7BjoIZm9vbzonTWVzc2FnZVZlcmlmaWVyVGVzdDo6QXV0b2xvYWRDbGFzcwY6CUBmb29JIghmb28GOgZFVA==--f3ef39a5241c365083770566dc7a9eb5d6ace914"
exception = assert_raise(ArgumentError, NameError) do
@verifier.verified(valid_message)
end
assert_includes ["uninitialized constant MessageVerifierTest::AutoloadClass",
"undefined class/module MessageVerifierTest::AutoloadClass"], exception.message
exception = assert_raise(ArgumentError, NameError) do
@verifier.verify(valid_message)
end
assert_includes ["uninitialized constant MessageVerifierTest::AutoloadClass",
"undefined class/module MessageVerifierTest::AutoloadClass"], exception.message
end
def test_raise_error_when_secret_is_nil
exception = assert_raise(ArgumentError) do
ActiveSupport::MessageVerifier.new(nil)
@ -96,12 +77,6 @@ class MessageVerifierTest < ActiveSupport::TestCase
assert_equal "Secret should not be nil.", exception.message
end
def test_backward_compatibility_messages_signed_without_metadata
signed_message = "BAh7BzoJc29tZUkiCWRhdGEGOgZFVDoIbm93SXU6CVRpbWUNIIAbgAAAAAAHOgtvZmZzZXRpADoJem9uZUkiCFVUQwY7BkY=--d03c52c91dfe4ccc5159417c660461bcce005e96"
assert_equal @data, @verifier.verify(signed_message)
end
def test_rotating_secret
old_message = ActiveSupport::MessageVerifier.new("old", digest: "SHA1").generate("old")
@ -124,6 +99,35 @@ class MessageVerifierTest < ActiveSupport::TestCase
assert_equal "older", verifier.verified(older_message)
end
def test_rotations_with_metadata
old_message = ActiveSupport::MessageVerifier.new("old").generate("old", purpose: :rotation)
verifier = ActiveSupport::MessageVerifier.new(@secret)
verifier.rotate "old"
assert_equal "old", verifier.verified(old_message, purpose: :rotation)
end
end
class DefaultMarshalSerializerMessageVerifierTest < MessageVerifierTest
def setup
@default_verifier = ActiveSupport::MessageVerifier.default_message_verifier_serializer
ActiveSupport::MessageVerifier.default_message_verifier_serializer = :marshal
@verifier = ActiveSupport::MessageVerifier.new("Hey, I'm a secret!")
@data = { some: "data", now: Time.utc(2010) }
@secret = SecureRandom.random_bytes(32)
end
def teardown
ActiveSupport::MessageVerifier.default_message_verifier_serializer = @default_verifier
end
def test_backward_compatibility_messages_signed_without_metadata
signed_message = "BAh7BzoJc29tZUkiCWRhdGEGOgZFVDoIbm93SXU6CVRpbWUNIIAbgAAAAAAHOgtvZmZzZXRpADoJem9uZUkiCFVUQwY7BkY=--d03c52c91dfe4ccc5159417c660461bcce005e96"
assert_equal @data, @verifier.verify(signed_message)
end
def test_on_rotation_is_called_and_verified_returns_message
older_message = ActiveSupport::MessageVerifier.new("older", digest: "SHA1").generate({ encoded: "message" })
@ -138,13 +142,127 @@ class MessageVerifierTest < ActiveSupport::TestCase
assert rotated
end
def test_rotations_with_metadata
old_message = ActiveSupport::MessageVerifier.new("old").generate("old", purpose: :rotation)
def test_raise_error_when_argument_class_is_not_loaded
# To generate the valid message below:
#
# AutoloadClass = Struct.new(:foo)
# valid_message = @verifier.generate(foo: AutoloadClass.new('foo'))
#
valid_message = "BAh7BjoIZm9vbzonTWVzc2FnZVZlcmlmaWVyVGVzdDo6QXV0b2xvYWRDbGFzcwY6CUBmb29JIghmb28GOgZFVA==--f3ef39a5241c365083770566dc7a9eb5d6ace914"
exception = assert_raise(ArgumentError, NameError) do
@verifier.verified(valid_message)
end
assert_includes ["uninitialized constant MessageVerifierTest::AutoloadClass",
"undefined class/module MessageVerifierTest::AutoloadClass"], exception.message
exception = assert_raise(ArgumentError, NameError) do
@verifier.verify(valid_message)
end
assert_includes ["uninitialized constant MessageVerifierTest::AutoloadClass",
"undefined class/module MessageVerifierTest::AutoloadClass"], exception.message
end
end
verifier = ActiveSupport::MessageVerifier.new(@secret)
verifier.rotate "old"
class MarshalSerializeAndFallbackMessageVerifierTest < DefaultMarshalSerializerMessageVerifierTest
def setup
@default_verifier = ActiveSupport::MessageVerifier.default_message_verifier_serializer
@default_use_marshal = ActiveSupport::JsonWithMarshalFallback.use_marshal_serialization
@default_fallback = ActiveSupport::JsonWithMarshalFallback.fallback_to_marshal_deserialization
ActiveSupport::MessageVerifier.default_message_verifier_serializer = :hybrid
ActiveSupport::JsonWithMarshalFallback.use_marshal_serialization = true
ActiveSupport::JsonWithMarshalFallback.fallback_to_marshal_deserialization = true
assert_equal "old", verifier.verified(old_message, purpose: :rotation)
@verifier = ActiveSupport::MessageVerifier.new("Hey, I'm a secret!")
@data = { some: "data", now: Time.utc(2010) }
@secret = SecureRandom.random_bytes(32)
end
def teardown
ActiveSupport::MessageVerifier.default_message_verifier_serializer = @default_verifier
ActiveSupport::JsonWithMarshalFallback.use_marshal_serialization = @default_use_marshal
ActiveSupport::JsonWithMarshalFallback.fallback_to_marshal_deserialization = @default_fallback
end
end
class JsonSerializeMarshalFallbackMessageVerifierTest < MessageVerifierTest
def setup
@default_verifier = ActiveSupport::MessageVerifier.default_message_verifier_serializer
@default_use_marshal = ActiveSupport::JsonWithMarshalFallback.use_marshal_serialization
@default_fallback = ActiveSupport::JsonWithMarshalFallback.fallback_to_marshal_deserialization
ActiveSupport::MessageVerifier.default_message_verifier_serializer = :hybrid
ActiveSupport::JsonWithMarshalFallback.use_marshal_serialization = false
ActiveSupport::JsonWithMarshalFallback.fallback_to_marshal_deserialization = true
@verifier = ActiveSupport::MessageVerifier.new("Hey, I'm a secret!")
@data = { "some" => "data", "now" => Time.utc(2010) }
@secret = SecureRandom.random_bytes(32)
end
def teardown
ActiveSupport::MessageVerifier.default_message_verifier_serializer = @default_verifier
ActiveSupport::JsonWithMarshalFallback.use_marshal_serialization = @default_use_marshal
ActiveSupport::JsonWithMarshalFallback.fallback_to_marshal_deserialization = @default_fallback
end
def test_on_rotation_is_called_and_verified_returns_message
older_message = ActiveSupport::MessageVerifier.new("older", digest: "SHA1").generate({ encoded: "message" })
verifier = ActiveSupport::MessageVerifier.new(@secret, digest: "SHA512")
verifier.rotate "old", digest: "SHA256"
verifier.rotate "older", digest: "SHA1"
rotated = false
message = verifier.verified(older_message, on_rotation: proc { rotated = true })
assert_equal({ "encoded" => "message" }, message)
assert rotated
end
def test_backward_compatibility_messages_signed_marshal_serialized
marshal_serialized_signed_message = "BAh7B0kiCXNvbWUGOgZFVEkiCWRhdGEGOwBUSSIIbm93BjsAVEl1OglUaW1lDSCAG8AAAAAABjoJem9uZUkiCFVUQwY7AEY=--ae7480422168507f4a8aec6b1d68bfdfd5c6ef48"
assert_equal @data, @verifier.verify(marshal_serialized_signed_message)
end
end
class JsonSerializeAndNoFallbackMessageVerifierTest < JsonSerializeMarshalFallbackMessageVerifierTest
def setup
@default_verifier = ActiveSupport::MessageVerifier.default_message_verifier_serializer
@default_use_marshal = ActiveSupport::JsonWithMarshalFallback.use_marshal_serialization
@default_fallback = ActiveSupport::JsonWithMarshalFallback.fallback_to_marshal_deserialization
ActiveSupport::MessageVerifier.default_message_verifier_serializer = :hybrid
ActiveSupport::JsonWithMarshalFallback.use_marshal_serialization = false
ActiveSupport::JsonWithMarshalFallback.fallback_to_marshal_deserialization = false
@verifier = ActiveSupport::MessageVerifier.new("Hey, I'm a secret!")
@data = { "some" => "data", "now" => Time.utc(2010) }
@secret = SecureRandom.random_bytes(32)
end
def teardown
ActiveSupport::MessageVerifier.default_message_verifier_serializer = @default_verifier
ActiveSupport::JsonWithMarshalFallback.use_marshal_serialization = @default_use_marshal
ActiveSupport::JsonWithMarshalFallback.fallback_to_marshal_deserialization = @default_fallback
end
def test_backward_compatibility_messages_signed_marshal_serialized
marshal_serialized_signed_message = "BAh7B0kiCXNvbWUGOgZFVEkiCWRhdGEGOwBUSSIIbm93BjsAVEl1OglUaW1lDSCAG8AAAAAABjoJem9uZUkiCFVUQwY7AEY=--ae7480422168507f4a8aec6b1d68bfdfd5c6ef48"
assert_raise(JSON::ParserError) do
@verifier.verify(marshal_serialized_signed_message)
end
end
end
class DefaultJsonSerializerMessageVerifierTest < JsonSerializeAndNoFallbackMessageVerifierTest
def setup
@default_verifier = ActiveSupport::MessageVerifier.default_message_verifier_serializer
ActiveSupport::MessageVerifier.default_message_verifier_serializer = :json
@verifier = ActiveSupport::MessageVerifier.new("Hey, I'm a secret!")
@data = { "some" => "data", "now" => Time.utc(2010) }
@secret = SecureRandom.random_bytes(32)
end
def teardown
ActiveSupport::MessageVerifier.default_message_verifier_serializer = @default_verifier
end
end
@ -199,7 +317,22 @@ class MessageVerifierMetadataMarshalTest < MessageVerifierMetadataTest
end
end
class MessageVerifierMetadataJSONTest < MessageVerifierMetadataTest
class MessageVerifierMetadataJsonWithMarshalFallbackTest < MessageVerifierMetadataTest
private
def verifier_options
{ serializer: ActiveSupport::JsonWithMarshalFallback }
end
end
class MessageVerifierMetadataJsonTest < MessageVerifierMetadataTest
private
def verifier_options
{ serializer: JSON }
end
end
class MessageVerifierMetadataCustomJSONTest < MessageVerifierMetadataTest
private
def verifier_options
{ serializer: MessageVerifierTest::JSONSerializer.new }

View File

@ -63,6 +63,7 @@ Below are the default values associated with each target version. In cases of co
- [`config.action_dispatch.default_headers`](#config-action-dispatch-default-headers): `{ "X-Frame-Options" => "SAMEORIGIN", "X-XSS-Protection" => "0", "X-Content-Type-Options" => "nosniff", "X-Permitted-Cross-Domain-Policies" => "none", "Referrer-Policy" => "strict-origin-when-cross-origin" }`
- [`config.add_autoload_paths_to_load_path`](#config-add-autoload-paths-to-load-path): `false`
- [`config.active_support.default_message_encryptor_serializer`](#config-active-support-default-message-encryptor-serializer): `:json`
- [`config.active_support.default_message_verifier_serializer`](#config-active-support-default-message-verifier-serializer): `:json`
#### Default Values for Target Version 7.0
@ -1909,6 +1910,19 @@ Used to help migrate apps from `Marshal` to `JSON` as the default serializer for
Defaults to `true`.
#### `config.active_support.default_message_verifier_serializer`
Specifies what serializer the `MessageVerifier` class will use by default.
Options are `:json`, `:hybrid`, and `:marshal`. `:hybrid` uses the `JsonWithMarshalFallback` class.
The default value depends on the `config.load_defaults` target version:
| Starting with version | The default value is |
| --------------------- | -------------------- |
| (original) | `:marshal` |
| 7.1 | `:json` |
### Configuring Active Job
`config.active_job` provides the following configuration options:

View File

@ -169,6 +169,85 @@ Alternatively, you could load defaults for 7.1
config.load_defaults 7.1
```
### New `ActiveSupport::MessageVerifier` default serializer
As of Rails 7.1, the default serializer in use by the `MessageVerifier` is `JSON`.
This offers a more secure alternative to the current default serializer.
The `MessageVerifier` offers the ability to migrate the default serializer from `Marshal` to `JSON`.
If you would like to ignore this change in existing applications, set the following: `config.active_support.default_message_verifier_serializer = :marshal`.
In order to roll out the new default when upgrading from `7.0` to `7.1`, there are three configuration variables to keep in mind.
```
config.active_support.default_verifier_serializer
config.active_support.fallback_to_marshal_deserialization
config.active_support.use_marshal_serialization
```
`default_message_verifier_serializer` defaults to `:json` as of `7.1` but it offers both a `:hybrid` and `:marshal` option.
In order to migrate an older deployment to `:json`, first ensure that the `default_message_verifier_serializer` is set to `:marshal`.
```ruby
# config/application.rb
config.load_defaults 7.0
config.active_support.default_message_verifier_serializer = :marshal
```
Once this is deployed on all Rails processes, set `default_message_verifier_serializer` to `:hybrid` to begin using the
`ActiveSupport::JsonWithMarshalFallback` class as the serializer. The defaults for this class are to use `Marshal`
as the serializer and to allow the deserialisation of both `Marshal` and `JSON` serialized payloads.
```ruby
config.load_defaults 7.0
config.active_support.default_message_verifier_serializer = :hybrid
```
Once this is deployed on all Rails processes, set the following configuration options in order to stop the
`ActiveSupport::JsonWithMarshalFallback` class from using `Marshal` to serialize new payloads.
```ruby
# config/application.rb
config.load_defaults 7.0
config.active_support.default_message_verifier_serializer = :hybrid
config.active_support.use_marshal_serialization = false
```
Allow this configuration to run on all processes for a considerable amount of time.
`ActiveSupport::JsonWithMarshalFallback` logs the following each time the `Marshal` fallback
is used:
```
JsonWithMarshalFallback: Marshal load fallback occurred.
```
Once those message stop appearing in your logs and you're confident that all `MessageVerifier`
payloads in transit are `JSON` serialized, the following configuration options will disable the
Marshal fallback in `ActiveSupport::JsonWithMarshalFallback`.
```ruby
# config/application.rb
config.load_defaults 7.0
config.active_support.default_message_verifier_serializer = :hybrid
config.active_support.use_marshal_serialization = false
config.active_support.fallback_to_marshal_deserialization = false
```
If all goes well, you should now be safe to migrate the Message Verifier from
`ActiveSupport::JsonWithMarshalFallback` to `ActiveSupport::JSON`.
To do so, simply swap the `:hybrid` serializer for the `:json` serializer.
```ruby
# config/application.rb
config.load_defaults 7.0
config.active_support.default_message_verifier_serializer = :json
```
Alternatively, you could load defaults for 7.1
```ruby
# config/application.rb
config.load_defaults 7.1
```
Upgrading from Rails 6.1 to Rails 7.0
-------------------------------------

View File

@ -270,6 +270,7 @@ module Rails
if respond_to?(:active_support)
active_support.default_message_encryptor_serializer = :json
active_support.default_message_verifier_serializer = :json
end
else
raise "Unknown version #{target_version.to_s.inspect}"

View File

@ -3189,6 +3189,14 @@ module ApplicationTests
assert_equal true, ActiveSupport::JsonWithMarshalFallback.fallback_to_marshal_deserialization
end
test "ActiveSupport::JsonWithMarshalFallback.fallback_to_marshal_deserialization is true by default for upgraded apps" do
remove_from_config '.*config\.load_defaults.*\n'
app "development"
assert_equal true, ActiveSupport::JsonWithMarshalFallback.fallback_to_marshal_deserialization
end
test "ActiveSupport::JsonWithMarshalFallback.fallback_to_marshal_deserialization can be configured via config.active_support.fallback_to_marshal_deserialization" do
remove_from_config '.*config\.load_defaults.*\n'
@ -3207,6 +3215,14 @@ module ApplicationTests
assert_equal true, ActiveSupport::JsonWithMarshalFallback.use_marshal_serialization
end
test "ActiveSupport::JsonWithMarshalFallback.use_marshal_serialization is true by default for upgraded apps" do
remove_from_config '.*config\.load_defaults.*\n'
app "development"
assert_equal true, ActiveSupport::JsonWithMarshalFallback.use_marshal_serialization
end
test "ActiveSupport::JsonWithMarshalFallback.use_marshal_serialization can be configured via config.active_support.use_marshal_serialization" do
remove_from_config '.*config\.load_defaults.*\n'
@ -3246,6 +3262,32 @@ module ApplicationTests
assert_equal :hybrid, ActiveSupport::MessageEncryptor.default_message_encryptor_serializer
end
test "ActiveSupport::MessageVerifier.default_message_verifier_serializer is :json by default for new apps" do
app "development"
assert_equal :json, ActiveSupport::MessageVerifier.default_message_verifier_serializer
end
test "ActiveSupport::MessageVerifier.default_message_verifier_serializer is :marshal by default for upgraded apps" do
remove_from_config '.*config\.load_defaults.*\n'
app "development"
assert_equal :marshal, ActiveSupport::MessageVerifier.default_message_verifier_serializer
end
test "ActiveSupport::MessageVerifier.default_message_verifier_serializer can be configured via config.active_support.default_message_verifier_serializer" do
remove_from_config '.*config\.load_defaults.*\n'
app_file "config/initializers/default_message_verifier_serializer.rb", <<-RUBY
Rails.application.config.active_support.default_message_verifier_serializer = :hybrid
RUBY
app "development"
assert_equal :hybrid, ActiveSupport::MessageVerifier.default_message_verifier_serializer
end
test "unknown_asset_fallback is false by default" do
app "development"

View File

@ -51,7 +51,7 @@ module ApplicationTests
assert_equal false, ActionDispatch::Cookies::CookieJar.always_write_cookie
end
test "signed cookies with SHA512 digest and rotated out SHA256 and SHA1 digests" do
test "signed cookies with SHA512 digest and marshal serializer and rotated out SHA256 and SHA1 digests" do
app_file "config/routes.rb", <<-RUBY
Rails.application.routes.draw do
get ':controller(/:action)'
@ -88,8 +88,8 @@ module ApplicationTests
sha256_secret = Rails.application.key_generator.generate_key("sha256")
::TestVerifiers = Class.new do
class_attribute :sha1, default: ActiveSupport::MessageVerifier.new(sha1_secret, digest: "SHA1")
class_attribute :sha256, default: ActiveSupport::MessageVerifier.new(sha256_secret, digest: "SHA256")
class_attribute :sha1, default: ActiveSupport::MessageVerifier.new(sha1_secret, digest: "SHA1", serializer: Marshal)
class_attribute :sha256, default: ActiveSupport::MessageVerifier.new(sha256_secret, digest: "SHA256", serializer: Marshal)
end
config.action_dispatch.signed_cookie_digest = "SHA512"
@ -104,7 +104,77 @@ module ApplicationTests
require "#{app_path}/config/environment"
verifier_sha512 = ActiveSupport::MessageVerifier.new(app.key_generator.generate_key("sha512 salt"), digest: :SHA512)
verifier_sha512 = ActiveSupport::MessageVerifier.new(app.key_generator.generate_key("sha512 salt"), digest: :SHA512, serializer: Marshal)
get "/foo/write_raw_cookie_sha1"
get "/foo/read_signed"
assert_equal "signed cookie".inspect, last_response.body
get "/foo/read_raw_cookie"
assert_equal "signed cookie", verifier_sha512.verify(last_response.body, purpose: "cookie.signed_cookie")
get "/foo/write_raw_cookie_sha256"
get "/foo/read_signed"
assert_equal "signed cookie".inspect, last_response.body
get "/foo/read_raw_cookie"
assert_equal "signed cookie", verifier_sha512.verify(last_response.body, purpose: "cookie.signed_cookie")
end
test "signed cookies with SHA512 digest and json serializer and rotated out SHA256 and SHA1 digests" do
app_file "config/routes.rb", <<-RUBY
Rails.application.routes.draw do
get ':controller(/:action)'
post ':controller(/:action)'
end
RUBY
controller :foo, <<-RUBY
class FooController < ActionController::Base
protect_from_forgery with: :null_session
def write_raw_cookie_sha1
cookies[:signed_cookie] = TestVerifiers.sha1.generate("signed cookie")
head :ok
end
def write_raw_cookie_sha256
cookies[:signed_cookie] = TestVerifiers.sha256.generate("signed cookie")
head :ok
end
def read_signed
render plain: cookies.signed[:signed_cookie].inspect
end
def read_raw_cookie
render plain: cookies[:signed_cookie]
end
end
RUBY
add_to_config <<-RUBY
sha1_secret = Rails.application.key_generator.generate_key("sha1")
sha256_secret = Rails.application.key_generator.generate_key("sha256")
::TestVerifiers = Class.new do
class_attribute :sha1, default: ActiveSupport::MessageVerifier.new(sha1_secret, digest: "SHA1", serializer: JSON)
class_attribute :sha256, default: ActiveSupport::MessageVerifier.new(sha256_secret, digest: "SHA256", serializer: JSON)
end
config.action_dispatch.signed_cookie_digest = "SHA512"
config.action_dispatch.signed_cookie_salt = "sha512 salt"
config.action_dispatch.cookies_serializer = :json
config.action_dispatch.cookies_rotations.tap do |cookies|
cookies.rotate :signed, sha1_secret, digest: "SHA1"
cookies.rotate :signed, sha256_secret, digest: "SHA256"
end
RUBY
require "#{app_path}/config/environment"
verifier_sha512 = ActiveSupport::MessageVerifier.new(app.key_generator.generate_key("sha512 salt"), digest: :SHA512, serializer: JSON)
get "/foo/write_raw_cookie_sha1"
get "/foo/read_signed"