class ActiveSupport::MessageEncryptor
MessageEncryptor — простой способ шифрования значений, которые хранятся в ненадежном месте.
Шифрованный текст и вектор инициализации кодируются в base64 и возвращаются вам.
Это может быть использовано в ситуациях, аналогичных MessageVerifier, но где вы не хотите, чтобы пользователи могли определить значение полезной нагрузки.
len = ActiveSupport::MessageEncryptor.key_len
salt = SecureRandom.random_bytes(len)
key = ActiveSupport::KeyGenerator.new('password').generate_key(salt, len) # => "\x89\xE0\x156\xAC..."
crypt = ActiveSupport::MessageEncryptor.new(key) # => #<ActiveSupport::MessageEncryptor ...>
encrypted_data = crypt.encrypt_and_sign('my secret data') # => "NlFBTTMwOUV5UlA1QlNEN2xkY2d6eThYWWh..."
crypt.decrypt_and_verify(encrypted_data) # => "my secret data"
Ограничение сообщений конкретной целью
По умолчанию любое сообщение может быть использовано в вашем приложении. Но они также могут быть ограничены конкретной :purpose.
token = crypt.encrypt_and_sign("this is the chair", purpose: :login)
Затем для извлечения данных при проверке необходимо передать ту же цель:
crypt.decrypt_and_verify(token, purpose: :login) # => "this is the chair" crypt.decrypt_and_verify(token, purpose: :shipping) # => nil crypt.decrypt_and_verify(token) # => nil
Также, если сообщение не имеет цели, оно не будет возвращено при проверке с указанием конкретной цели.
token = crypt.encrypt_and_sign("the conversation is lively")
crypt.decrypt_and_verify(token, purpose: :scare_tactics) # => nil
crypt.decrypt_and_verify(token) # => "the conversation is lively"
Установка срока действия сообщений
По умолчанию сообщения действуют вечно, и проверка через год всё ещё вернёт исходное значение. Но сообщения могут быть настроены на истечение в определённое время с помощью :expires_in или :expires_at.
crypt.encrypt_and_sign(parcel, expires_in: 1.month) crypt.encrypt_and_sign(doowad, expires_at: Time.now.end_of_year)
Затем сообщения могут быть проверены и возвращены до времени истечения срока действия. После этого проверка возвращает nil.
Ротация ключей
MessageEncryptor также поддерживает ротацию старых конфигураций, используя стек шифровальщиков. Вызовите rotate для построения и добавления шифровальщика, чтобы decrypt_and_verify также попробовал резервный вариант.
По умолчанию все ротированные шифровальщики используют значения основного шифровальщика, если не указано иное.
Вы бы задали новые значения по умолчанию своему шифровальщику:
crypt = ActiveSupport::MessageEncryptor.new(@secret, cipher: "aes-256-gcm")
Затем постепенно выведите старые значения из оборота, добавив их как резервные варианты. Любое сообщение, сгенерированное со старыми значениями, будет работать до тех пор, пока ротация не будет удалена.
crypt.rotate old_secret # Fallback to an old secret instead of @secret. crypt.rotate cipher: "aes-256-cbc" # Fallback to an old cipher instead of aes-256-gcm.
Однако, если как секрет, так и шифр были изменены одновременно, вышеуказанное следует объединить в:
crypt.rotate old_secret, cipher: "aes-256-cbc"
Константы
- OpenSSLCipherError
Публичные методы класса
# File activesupport/lib/active_support/message_encryptor.rb, line 161 def self.key_len(cipher = default_cipher) OpenSSL::Cipher.new(cipher).key_len end
Для заданного шифра возвращает длину ключа шифра, чтобы помочь сгенерировать ключ нужного размера
# File activesupport/lib/active_support/message_encryptor.rb, line 137 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] || self.class.default_cipher @digest = options[:digest] || "SHA1" unless aead_mode? @verifier = resolve_verifier @serializer = options[:serializer] || Marshal end
Инициализирует новый MessageEncryptor. secret должен быть не короче, чем размер ключа шифра. Для стандартного шифра 'aes-256-gcm' это 256 бит. Если вы используете секрет, введённый пользователем, вы можете сгенерировать подходящий ключ с помощью ActiveSupport::KeyGenerator или аналогичной функции вывода ключа.
Первый дополнительный параметр используется в качестве ключа подписи для MessageVerifier. Это позволяет вам указывать ключи для шифрования и подписи данных.
ActiveSupport::MessageEncryptor.new('secret', 'signature_secret')
Параметры:
-
:cipher- Шифр для использования. Может быть любым шифром, возвращаемымOpenSSL::Cipher.ciphers. По умолчанию 'aes-256-gcm'. -
:digest- Строка хэша для использования при подписи. По умолчаниюSHA1. Игнорируется при использовании шифра AEAD, такого как 'aes-256-gcm'. -
:serializer- Сериализатор объектов для использования. По умолчаниюMarshal.
Публичные методы экземпляра
# File activesupport/lib/active_support/message_encryptor.rb, line 156 def decrypt_and_verify(data, purpose: nil, **) _decrypt(verifier.verify(data), purpose) end
Дешифрует и проверяет сообщение. Мы должны проверить сообщение, чтобы избежать атак с использованием заполнения. Ссылка: www.limited-entropy.com/padding-oracle-attacks/.
# File activesupport/lib/active_support/message_encryptor.rb, line 150 def encrypt_and_sign(value, expires_at: nil, expires_in: nil, purpose: nil) verifier.generate(_encrypt(value, expires_at: expires_at, expires_in: expires_in, purpose: purpose)) end
Шифрует и подписывает сообщение. Мы должны подписать сообщение, чтобы избежать атак с использованием заполнения. Ссылка: www.limited-entropy.com/padding-oracle-attacks/.
© 2004–2018 David Heinemeier Hansson
Licensed under the MIT License.