diff options
author | Santiago Pastorino <santiago@wyeworks.com> | 2012-11-15 12:17:25 -0800 |
---|---|---|
committer | Santiago Pastorino <santiago@wyeworks.com> | 2012-11-15 12:17:25 -0800 |
commit | ef8b845de7e06077131297a398cb7f4e81d6bb08 (patch) | |
tree | b1e54d87132a561f1a5ad4b61a2eea28de4b26dc /activesupport | |
parent | cf3eb6dab0e89ea6b64b9bdb24d4df3e8006da7b (diff) | |
parent | d63783983f8c03d5c624938081615579dcc753f7 (diff) | |
download | rails-ef8b845de7e06077131297a398cb7f4e81d6bb08.tar.gz rails-ef8b845de7e06077131297a398cb7f4e81d6bb08.tar.bz2 rails-ef8b845de7e06077131297a398cb7f4e81d6bb08.zip |
Merge pull request #8112 from rails/encrypted_cookies
Encrypted cookies
Diffstat (limited to 'activesupport')
-rw-r--r-- | activesupport/lib/active_support/key_generator.rb | 48 | ||||
-rw-r--r-- | activesupport/lib/active_support/message_encryptor.rb | 7 | ||||
-rw-r--r-- | activesupport/test/message_encryptor_test.rb | 2 |
3 files changed, 54 insertions, 3 deletions
diff --git a/activesupport/lib/active_support/key_generator.rb b/activesupport/lib/active_support/key_generator.rb index 04d170f801..2c8fccec7d 100644 --- a/activesupport/lib/active_support/key_generator.rb +++ b/activesupport/lib/active_support/key_generator.rb @@ -1,3 +1,4 @@ +require 'mutex_m' require 'openssl' module ActiveSupport @@ -20,4 +21,51 @@ module ActiveSupport OpenSSL::PKCS5.pbkdf2_hmac_sha1(@secret, salt, @iterations, key_size) end end + + class CachingKeyGenerator + def initialize(key_generator) + @key_generator = key_generator + @cache_keys = {}.extend(Mutex_m) + end + + def generate_key(salt, key_size=64) + @cache_keys.synchronize do + @cache_keys["#{salt}#{key_size}"] ||= @key_generator.generate_key(salt, key_size) + end + end + end + + class DummyKeyGenerator + SECRET_MIN_LENGTH = 30 # Characters + + def initialize(secret) + ensure_secret_secure(secret) + @secret = secret + end + + def generate_key(salt) + @secret + end + + private + + # To prevent users from using something insecure like "Password" we make sure that the + # secret they've provided is at least 30 characters in length. + def ensure_secret_secure(secret) + if secret.blank? + raise ArgumentError, "A secret is required to generate an " + + "integrity hash for cookie session data. Use " + + "config.secret_key_base = \"some secret phrase of at " + + "least #{SECRET_MIN_LENGTH} characters\"" + + "in config/initializers/secret_token.rb" + end + + if secret.length < SECRET_MIN_LENGTH + raise ArgumentError, "Secret should be something secure, " + + "like \"#{SecureRandom.hex(16)}\". The value you " + + "provided, \"#{secret}\", is shorter than the minimum length " + + "of #{SECRET_MIN_LENGTH} characters" + end + end + end end diff --git a/activesupport/lib/active_support/message_encryptor.rb b/activesupport/lib/active_support/message_encryptor.rb index 580267708c..1588674afc 100644 --- a/activesupport/lib/active_support/message_encryptor.rb +++ b/activesupport/lib/active_support/message_encryptor.rb @@ -39,10 +39,13 @@ module ActiveSupport # * <tt>:cipher</tt> - Cipher to use. Can be any cipher returned by # <tt>OpenSSL::Cipher.ciphers</tt>. Default is 'aes-256-cbc'. # * <tt>:serializer</tt> - Object serializer to use. Default is +Marshal+. - def initialize(secret, options = {}) + def initialize(secret, *signature_key_or_options) + options = signature_key_or_options.extract_options! + sign_secret = signature_key_or_options.first @secret = secret + @sign_secret = sign_secret @cipher = options[:cipher] || 'aes-256-cbc' - @verifier = MessageVerifier.new(@secret, :serializer => NullSerializer) + @verifier = MessageVerifier.new(@sign_secret || @secret, :serializer => NullSerializer) @serializer = options[:serializer] || Marshal end diff --git a/activesupport/test/message_encryptor_test.rb b/activesupport/test/message_encryptor_test.rb index b544742300..d6c31396b6 100644 --- a/activesupport/test/message_encryptor_test.rb +++ b/activesupport/test/message_encryptor_test.rb @@ -56,7 +56,7 @@ class MessageEncryptorTest < ActiveSupport::TestCase end def test_alternative_serialization_method - encryptor = ActiveSupport::MessageEncryptor.new(SecureRandom.hex(64), :serializer => JSONSerializer.new) + encryptor = ActiveSupport::MessageEncryptor.new(SecureRandom.hex(64), SecureRandom.hex(64), :serializer => JSONSerializer.new) message = encryptor.encrypt_and_sign({ :foo => 123, 'bar' => Time.utc(2010) }) assert_equal encryptor.decrypt_and_verify(message), { "foo" => 123, "bar" => "2010-01-01T00:00:00Z" } end |