Spec-Zone.ru › Ruby on Rails 7.2

класс ActiveSupport::MessageEncryptor

Родитель:
Messages::Codec

Шифровальщик сообщений Active Support

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"

Метод decrypt_and_verify вызовет исключение ActiveSupport::MessageEncryptor::InvalidMessage, если предоставленные данные нельзя расшифровать или проверить.

crypt.decrypt_and_verify('not encrypted data') # => ActiveSupport::MessageEncryptor::InvalidMessage

Ограничение сообщений конкретной целью

По умолчанию любое сообщение может использоваться в приложении. Но сообщения также могут быть ограничены определённой :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

Публичные методы класса

key_len(cipher = default_cipher) Показать исходный код
# File activesupport/lib/active_support/message_encryptor.rb, line 252
def self.key_len(cipher = default_cipher)
  OpenSSL::Cipher.new(cipher).key_len
end

Для заданного шифра возвращает длину ключа шифра, чтобы помочь в генерации ключа нужной длины.

new(secret, sign_secret = nil, **options) Показать исходный код
# File activesupport/lib/active_support/message_encryptor.rb, line 183
def initialize(secret, sign_secret = nil, **options)
  super(**options)
  @secret = secret
  @cipher = options[:cipher] || self.class.default_cipher
  @aead_mode = new_cipher.authenticated?
  @verifier = if !@aead_mode
    MessageVerifier.new(sign_secret || secret, **options, serializer: NullSerializer)
  end
end

Инициализирует новый MessageEncryptor. secret должен быть не меньше размера ключа шифра. Для шифра по умолчанию ‘aes-256-gcm’ он составляет 256 бит. Если вы используете секрет, введённый пользователем, вы можете сгенерировать подходящий ключ, используя ActiveSupport::KeyGenerator или аналогичную функцию вывода ключа.

Первый дополнительный параметр используется в качестве ключа подписи для MessageVerifier. Это позволяет вам указать ключи для шифрования и подписи данных. Игнорируется при использовании шифра AEAD, такого как ‘aes-256-gcm’.

ActiveSupport::MessageEncryptor.new('secret', 'signature_secret')

Параметры

:cipher

Используемый шифр. Может быть любым шифром, возвращаемым OpenSSL::Cipher.ciphers. По умолчанию ‘aes-256-gcm’.

:digest

Digest используемый для подписи. Игнорируется при использовании шифра AEAD, такого как ‘aes-256-gcm’.

:serializer

Сериализатор, используемый для сериализации данных сообщения. Вы можете указать любой объект, который отвечает на dump и load, или выбрать один из нескольких предварительно настроенных сериализаторов: :marshal, :json_allow_marshal, :json, :message_pack_allow_marshal, :message_pack.

Предварительно настроенные сериализаторы включают механизм обратного вызова для поддержки нескольких форматов десериализации. Например, сериализатор :marshal будет сериализовать с использованием Marshal, но может десериализовать с использованием Marshal, ActiveSupport::JSON или ActiveSupport::MessagePack. Это упрощает миграцию между сериализаторами.

Сериализаторы :marshal, :json_allow_marshal, и :message_pack_allow_marshal поддерживают десериализацию с использованием Marshal, но другие — нет. Имейте в виду, что Marshal является потенциальным вектором атак десериализации в случаях, когда был скомпрометирован секрет подписи сообщения. Если возможно, выберите сериализатор, который не поддерживает Marshal.

Сериализаторы :message_pack и :message_pack_allow_marshal используют ActiveSupport::MessagePack, который может обращать в обратном направлении некоторые типы Ruby, которые не поддерживаются JSON, и может обеспечить улучшенную производительность. Однако для них требуется gem msgpack.

При использовании Rails значение по умолчанию зависит от config.active_support.message_serializer. В противном случае значением по умолчанию является :marshal.

:url_safe

По умолчанию MessageEncryptor генерирует строки, совместимые с RFC 4648, которые не являются URL-безопасными. Другими словами, они могут содержать “+” и “/”. Если вы хотите сгенерировать URL-безопасные строки (в соответствии с «Кодирование Base 64 с URL и безопасностью имён файлов» в RFC 4648), вы можете передать true.

:force_legacy_metadata_serializer

Использовать ли устаревший сериализатор метаданных, который сериализует сообщение сначала, а затем оборачивает его в конверт, который также сериализуется. Это было значением по умолчанию в Rails 7.0 и ниже.

Если вы не передадите истинное значение, значение по умолчанию устанавливается с помощью config.active_support.use_message_serializer_for_metadata.

Вызов метода суперкласса

Публичные методы экземпляра

decrypt_and_verify(message, **options) Показать исходный код
# File activesupport/lib/active_support/message_encryptor.rb, line 241
def decrypt_and_verify(message, **options)
  catch_and_raise :invalid_message_format, as: InvalidMessage do
    catch_and_raise :invalid_message_serialization, as: InvalidMessage do
      catch_and_ignore :invalid_message_content do
        read_message(message, **options)
      end
    end
  end
end

Расшифровывает и проверяет сообщение. Мы должны проверить сообщение, чтобы избежать атак с подделкой заполнения. См.: www.limited-entropy.com/padding-oracle-attacks/.

Параметры

:purpose

Цель, с которой было сгенерировано сообщение. Если цель не совпадает, decrypt_and_verify вернёт nil.

message = encryptor.encrypt_and_sign("hello", purpose: "greeting")
encryptor.decrypt_and_verify(message, purpose: "greeting") # => "hello"
encryptor.decrypt_and_verify(message)                      # => nil

message = encryptor.encrypt_and_sign("bye")
encryptor.decrypt_and_verify(message)                      # => "bye"
encryptor.decrypt_and_verify(message, purpose: "greeting") # => nil
encrypt_and_sign(value, **options) Показать исходный код
# File activesupport/lib/active_support/message_encryptor.rb, line 220
def encrypt_and_sign(value, **options)
  create_message(value, **options)
end

Шифрует и подписывает сообщение. Мы должны подписать сообщение, чтобы избежать атак с подделкой заполнения. См.: www.limited-entropy.com/padding-oracle-attacks/.

Параметры

:expires_at

Дата и время истечения срока действия сообщения. После этой даты и времени проверка сообщения завершится неудачей.

message = encryptor.encrypt_and_sign("hello", expires_at: Time.now.tomorrow)
encryptor.decrypt_and_verify(message) # => "hello"
# 24 hours later...
encryptor.decrypt_and_verify(message) # => nil
:expires_in

Продолжительность действия сообщения. После истечения этого срока проверка сообщения завершится неудачей.

message = encryptor.encrypt_and_sign("hello", expires_in: 24.hours)
encryptor.decrypt_and_verify(message) # => "hello"
# 24 hours later...
encryptor.decrypt_and_verify(message) # => nil
:purpose

Цель сообщения. Если указана, та же цель должна быть указана при проверке сообщения; в противном случае проверка завершится неудачей. (См. decrypt_and_verify.)

© 2004–2021 David Heinemeier Hansson
Licensed under the MIT License.

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API