Active Record 암호화

이 가이드는 Active Record를 사용하여 데이터베이스 정보를 암호화하는 방법을 다룹니다.

이 가이드를 읽고 나면 다음을 알 수 있습니다:

  • Active Record로 데이터베이스 암호화를 설정하는 방법.
  • 암호화되지 않은 데이터를 마이그레이션하는 방법.
  • 다양한 암호화 체계가 공존하도록 하는 방법.
  • API 사용 방법.
  • 라이브러리 구성 및 확장 방법.

Active Record는 애플리케이션 수준의 암호화를 지원합니다. 이는 어떤 속성을 암호화해야 하는지 선언하고, 필요할 때 투명하게 암호화 및 복호화하는 것입니다. 암호화 계층은 데이터베이스와 애플리케이션 사이에 있습니다. 애플리케이션은 암호화되지 않은 데이터에 액세스하지만, 데이터베이스에는 암호화된 데이터가 저장됩니다.

애플리케이션 수준에서 데이터를 암호화해야 하는 이유?

Active Record 암호화는 애플리케이션의 중요한 정보를 보호하기 위해 존재합니다. 일반적인 예는 사용자의 개인 식별 정보입니다. 그렇다면 데이터베이스 자체가 이미 암호화되어 있다면 애플리케이션 수준의 암호화를 왜 해야 할까요?

즉각적인 실용적 이점으로, 중요한 속성을 암호화하면 추가적인 보안 계층이 생깁니다. 예를 들어 공격자가 데이터베이스, 데이터베이스 스냅샷 또는 애플리케이션 로그에 액세스하더라도 암호화된 정보를 이해할 수 없습니다. 또한 암호화를 통해 개발자가 애플리케이션 로그에서 사용자의 중요한 데이터를 실수로 노출하는 것을 방지할 수 있습니다.

그러나 더 중요한 것은 Active Record 암호화를 사용하면 애플리케이션 코드 수준에서 중요한 정보를 정의할 수 있다는 것입니다. Active Record 암호화를 통해 애플리케이션 및 애플리케이션의 데이터를 소비하는 서비스에서 데이터 액세스를 세부적으로 제어할 수 있습니다. 예를 들어 암호화된 데이터를 보호하는 감사 가능한 Rails 콘솔을 고려해 보거나 컨트롤러 매개변수에 자동으로 필터링되는 내장 시스템을 확인해 보세요.

기본 사용법

설정

bin/rails db:encryption:init 명령을 실행하여 랜덤 키 세트를 생성합니다:

$ bin/rails db:encryption:init
대상 환경의 자격 증명에 다음 항목을 추가하세요:

active_record_encryption:
  primary_key: EGY8WhulUOXixybod7ZWwMIL68R9o5kC
  deterministic_key: aPA5XyALhf75NNnMzaspW7akTfZp0lPY
  key_derivation_salt: xEY0dt6TZcAMg52K7O84wYzkjvbA62Hz

이 값은 기존 Rails 자격 증명에 생성된 값을 복사하여 붙여넣어 저장할 수 있습니다. 또는 이러한 값을 환경 변수와 같은 다른 소스에서 구성할 수 있습니다:

config.active_record.encryption.primary_key = ENV['ACTIVE_RECORD_ENCRYPTION_PRIMARY_KEY']
config.active_record.encryption.deterministic_key = ENV['ACTIVE_RECORD_ENCRYPTION_DETERMINISTIC_KEY']
config.active_record.encryption.key_derivation_salt = ENV['ACTIVE_RECORD_ENCRYPTION_KEY_DERIVATION_SALT']

참고: 이렇게 생성된 값은 32바이트 길이입니다. 직접 생성하는 경우 기본 키는 최소 12바이트, 솔트는 최소 20바이트를 사용해야 합니다.

암호화된 속성 선언

암호화 가능한 속성은 모델 수준에서 정의됩니다. 이는 동일한 이름의 열로 백업되는 일반적인 Active Record 속성입니다.

class Article < ApplicationRecord
  encrypts :title
end

라이브러리는 이러한 속성을 투명하게 암호화하여 데이터베이스에 저장하고, 필요할 때 복호화합니다:

article = Article.create title: "Encrypt it all!"
article.title # => "Encrypt it all!"

그러나 내부적으로 실행된 SQL은 다음과 같습니다:

INSERT INTO `articles` (`title`) VALUES ('{\"p\":\"n7J0/ol+a7DRMeaE\",\"h\":{\"iv\":\"DXZMDWUKfp3bg/Yu\",\"at\":\"X1/YjMHbHD4talgF9dt61A==\"}}')

중요: 저장 및 열 크기에 대하여

암호화에는 Base64 인코딩과 암호화된 페이로드와 함께 저장되는 메타데이터로 인해 추가 공간이 필요합니다. 내장된 엔벨로프 암호화 키 공급자를 사용하는 경우 최악의 경우 오버헤드는 약 255바이트 정도로 추정할 수 있습니다. 이 오버헤드는 더 큰 크기에서는 무시할 수 있습니다. 단순히 희석되기 때문만이 아니라 라이브러리가 기본적으로 압축을 사용하여 더 큰 페이로드에 대해 최대 30%의 저장 공간 절감 효과를 제공하기 때문입니다.

문자열 열 크기에 대한 중요한 우려 사항이 있습니다: 현대 데이터베이스에서 열 크기는 문자 수를 결정하며 바이트 수가 아닙니다. 예를 들어 UTF-8에서 각 문자는 최대 4바이트를 차지할 수 있으므로, 잠재적으로 UTF-8을 사용하는 데이터베이스의 열은 바이트 수 기준으로 4배까지 저장할 수 있습니다. 이제 암호화된 페이로드는 Base64로 직렬화된 이진 문자열이므로 일반 string 열에 저장할 수 있습니다. ASCII 바이트 시퀀스이므로 암호화된 열은 일반 버전 크기의 4배까지 차지할 수 있습니다. 따라서 데이터베이스에 저장되는 바이트가 동일하더라도 열은 4배 더 커야 합니다.

실제로 이는 다음을 의미합니다:

  • 서구 알파벳(주로 ASCII 문자)으로 작성된 짧은 텍스트를 암호화할 때는 255바이트의 추가 오버헤드를 고려해야 합니다.
  • 키릴 문자와 같은 비서구 알파벳으로 작성된 짧은 텍스트를 암호화할 때는 열 크기를 4배 늘려야 합니다. 저장 오버헤드는 최대 255바이트입니다.
  • 긴 텍스트를 암호화할 때는 열 크기 문제를 무시할 수 있습니다.

몇 가지 예:

암호화할 내용 원래 열 크기 권장 암호화된 열 크기 최악의 경우 저장 오버헤드
이메일 주소 string(255) string(510) 255바이트
이모지 시퀀스 string(255) string(1020) 255바이트
비서구 알파벳으로 작성된 텍스트 요약 string(500) string(2000) 255바이트
임의의 긴 텍스트 text text 무시할 수 있음

결정론적 및 비결정론적 암호화

기본적으로 Active Record 암호화는 비결정론적 접근 방식을 사용합니다. 비결정론적이라는 의미는 동일한 비밀번호로 동일한 내용을 두 번 암호화하면 서로 다른 암호문이 생성된다는 것입니다. 이 접근 방식은 암호문 분석을 더 어렵게 만들고 데이터베이스 쿼리를 불가능하게 합니다.

deterministic: 옵션을 사용하면 초기화 벡터를 결정론적으로 생성하여 암호화된 데이터를 쿼리할 수 있습니다.

class Author < ApplicationRecord
  encrypts :email, deterministic: true
end

Author.find_by_email("some@email.com") # 모델을 정상적으로 쿼리할 수 있습니다.

비결정론적 접근 방식은 데이터를 쿼리할 필요가 없는 경우 권장됩니다.

참고: 비결정론적 모드에서 Active Record는 256비트 키와 랜덤 초기화 벡터를 사용하는 AES-GCM을 사용합니다. 결정론적 모드에서는 키와 암호화할 내용의 HMAC-SHA-256 다이제스트를 사용하여 초기화 벡터를 생성합니다.

참고: deterministic_key를 생략하면 결정론적 암호화를 비활성화할 수 있습니다.

기능

Action Text

encrypted: true 옵션을 전달하여 Action Text 속성을 암호화할 수 있습니다.

class Message < ApplicationRecord
  has_rich_text :content, encrypted: true
end

참고: Action Text 속성에 개별 암호화 옵션을 전달하는 것은 아직 지원되지 않습니다. 전역 암호화 옵션을 사용하여 비결정론적 암호화를 사용합니다.

픽스처

test.rb에 다음 옵션을 추가하여 Rails 픽스처를 자동으로 암호화할 수 있습니다:

config.active_record.encryption.encrypt_fixtures = true

이 옵션이 활성화되면 모델에 정의된 암호화 가능한 모든 속성이 암호화 설정에 따라 암호화됩니다.

Action Text 픽스처

Action Text 픽스처를 암호화하려면 fixtures/action_text/encrypted_rich_texts.yml에 배치해야 합니다.

지원되는 유형

active_record.encryption은 기본 유형을 사용하여 값을 직렬화한 다음 암호화하지만, 사용자 지정 message_serializer를 사용하지 않는 한 문자열로 직렬화할 수 있어야 합니다. serialized 와 같은 구조화된 유형은 기본적으로 지원됩니다.

사용자 지정 유형을 지원해야 하는 경우 직렬화된 속성을 사용하는 것이 권장되는 방법입니다. 직렬화된 속성 선언은 암호화 선언 전에 있어야 합니다:

# 올바른 방법
class Article < ApplicationRecord
  serialize :title, type: Title
  encrypts :title
end

# 잘못된 방법
class Article < ApplicationRecord
  encrypts :title
  serialize :title, type: Title
end

대소문자 무시

결정론적으로 암호화된 데이터를 쿼리할 때 대소문자를 무시해야 할 수 있습니다. 이를 더 쉽게 수행할 수 있는 두 가지 접근 방식이 있습니다:

암호화된 속성을 선언할 때 :downcase 옵션을 사용하여 암호화 전에 내용을 소문자로 변환할 수 있네, 계속해서 번역하겠습니다.

class Person
  encrypts :email_address, deterministic: true, downcase: true
end

:downcase 를 사용하면 원래 대소문자가 손실됩니다. 일부 상황에서는 쿼리 시에만 대소문자를 무시하고 원래 대소문자를 저장하고 싶을 수 있습니다. 이러한 상황에서는 :ignore_case 옵션을 사용할 수 있습니다. 이 경우 원본 대소문자를 저장하기 위해 original_<column_name> 이라는 새 열을 추가해야 합니다:

class Label
  encrypts :name, deterministic: true, ignore_case: true # 원래 대소문자가 `original_name` 열에 저장됩니다.
end

암호화되지 않은 데이터 지원

암호화되지 않은 데이터의 마이그레이션을 용이하게 하기 위해 라이브러리에는 config.active_record.encryption.support_unencrypted_data 옵션이 포함되어 있습니다. true로 설정하면:

  • 암호화되지 않은 상태로 저장된 암호화된 속성을 읽으려고 할 때 오류가 발생하지 않습니다.
  • 결정론적으로 암호화된 속성을 사용하는 쿼리에는 암호화되지 않은 “일반 텍스트” 버전이 포함됩니다. 이를 활성화하려면 config.active_record.encryption.extend_queries = true를 설정해야 합니다.

이 옵션은 전환 기간 동안 사용하도록 의도되었습니다. 일반 데이터와 암호화된 데이터가 공존해야 합니다. 둘 다 기본적으로 false로 설정되어 있으며, 이는 모든 애플리케이션에 대한 권장 목표입니다: 암호화되지 않은 데이터를 사용할 때 오류가 발생합니다.

이전 암호화 체계 지원

속성의 암호화 속성을 변경하면 기존 데이터가 손상될 수 있습니다. 예를 들어 결정론적 속성을 비결정론적으로 만들고 싶다고 가정해 보겠습니다. 모델에서 선언만 변경하면 기존 암호문을 읽을 수 없게 됩니다. 암호화 방법이 달라졌기 때문입니다.

이러한 상황을 지원하기 위해 이전 암호화 체계를 선언할 수 있습니다. 이는 두 가지 시나리오에서 사용됩니다:

  • 암호화된 데이터를 읽을 때 Active Record 암호화는 현재 체계가 작동하지 않으면 이전 암호화 체계를 시도합니다.
  • 결정론적 데이터를 쿼리할 때 이전 체계로 암호화된 암호문도 추가하여 다양한 체계로 암호화된 데이터와 원활하게 작동할 수 있습니다. 이를 활성화하려면 config.active_record.encryption.extend_queries = true를 설정해야 합니다.

이전 암호화 체계는 다음과 같이 구성할 수 있습니다:

  • 전역적으로
  • 속성별로

전역 이전 암호화 체계

application.rb에서 previous 구성 속성을 사용하여 이전 암호화 체계를 속성 목록으로 추가할 수 있습니다:

config.active_record.encryption.previous = [ { key_provider: MyOldKeyProvider.new } ]

속성별 암호화 체계

속성 선언에 :previous를 사용합니다:

class Article
  encrypts :title, deterministic: true, previous: { deterministic: false }
end

암호화 체계 및 결정론적 속성

이전 암호화 체계를 추가할 때:

  • 비결정론적 암호화의 경우 새 정보는 항상 최신(현재) 암호화 체계로 암호화됩니다.
  • 결정론적 암호화의 경우 새 정보는 기본적으로 가장 오래된 암호화 체계로 암호화됩니다.

일반적으로 결정론적 암호화에서는 암호문이 일정하게 유지되기를 원합니다. deterministic: { fixed: false }를 설정하면 이 동작을 변경할 수 있습니다. 그러면 새 데이터 암호화에 최신 암호화 체계를 사용합니다.

고유 제약 조건

참고: 고유 제약 조건은 결정론적으로 암호화된 데이터에서만 사용할 수 있습니다.

고유 유효성 검사

확장된 쿼리가 활성화되어 있으면(config.active_record.encryption.extend_queries = true) 고유 유효성 검사가 정상적으로 작동합니다.

class Person
  validates :email_address, uniqueness: true
  encrypts :email_address, deterministic: true, downcase: true
end

암호화된 데이터와 암호화되지 않은 데이터를 결합하거나 이전 암호화 체계를 구성할 때도 작동합니다.

참고: 대소문자를 무시하려면 encrypts 선언에서 downcase: 또는 ignore_case:를 사용해야 합니다. 유효성 검사에서 case_sensitive: 옵션을 사용하면 작동하지 않습니다.

고유 인덱스

결정론적으로 암호화된 열에 대한 고유 인덱스를 지원하려면 암호문이 절대 변경되지 않도록 해야 합니다.

이를 장려하기 위해 결정론적 속성은 여러 암호화 체계가 구성된 경우 기본적으로 가장 오래된 암호화 체계를 사용합니다. 그렇지 않으면 이러한 속성에 대한 암호화 속성이 변경되지 않도록 하는 것이 사용자의 책임입니다. 그렇지 않으면 고유 인덱스가 작동하지 않습니다.

class Person
  encrypts :email_address, deterministic: true
end

암호화된 열 이름으로 명명된 매개변수 필터링

기본적으로 암호화된 열은 Rails 로그에서 자동으로 필터링되도록 구성됩니다. 이 동작을 비활성화하려면 application.rb에 다음을 추가하세요:

config.active_record.encryption.add_to_filter_parameters = false

필터링이 활성화되어 있지만 특정 열을 자동 필터링에서 제외하려면 config.active_record.encryption.excluded_from_filter_parameters에 추가하세요:

config.active_record.encryption.excluded_from_filter_parameters = [:catchphrase]

필터 매개변수를 생성할 때 Rails는 모델 이름을 접두사로 사용합니다. 예: Person#name의 경우 필터 매개변수는 person.name입니다.

인코딩

라이브러리는 비결정론적으로 암호화된 문자열 값의 인코딩을 유지합니다.

인코딩은 암호화된 페이로드와 함께 저장되므로 결정론적으로 암호화된 값은 기본적으로 UTF-8 인코딩을 강제합니다. 따라서 다른 인코딩을 가진 동일한 값은 암호화될 때 다른 암호문이 됩니다. 일반적으로 쿼리와 고유성 제약 조건이 작동하도록 유지하려는 것이 좋으므로 라이브러리가 이를 자동으로 변환합니다.

결정론적 암호화에 대한 기본 인코딩을 다음과 같이 구성할 수 있습니다:

config.active_record.encryption.forced_encoding_for_deterministic_encryption = Encoding::US_ASCII

그리고 이 동작을 비활성화하고 모든 경우에 인코딩을 유지하려면 다음과 같이 설정할 수 있습니다:

config.active_record.encryption.forced_encoding_for_deterministic_encryption = nil

키 관리

키 공급자는 키 관리 전략을 구현합니다. 전역적으로 또는 속성별로 키 공급자를 구성할 수 있습니다.

내장 키 공급자

DerivedSecretKeyProvider

제공된 비밀번호를 사용하여 PBKDF2를 통해 키를 제공하는 키 공급자입니다.

config.active_record.encryption.key_provider = ActiveRecord::Encryption::DerivedSecretKeyProvider.new(["some passwords", "to derive keys from. ", "These should be in", "credentials"])

참고: 기본적으로 active_record.encryptionactive_record.encryption.primary_key에 정의된 키를 사용하는 DerivedSecretKeyProvider를 구성합니다.

EnvelopeEncryptionKeyProvider

엔벨로프 암호화 전략을 구현합니다:

  • 각 데이터 암호화 작업에 대해 랜덤 키를 생성합니다.
  • 자격 증명 active_record.encryption.primary_key에 정의된 기본 키로 암호화된 데이터 키를 데이터 자체와 함께 저장합니다.

application.rb에 다음을 추가하여 Active Record가 이 키 공급자를 사용하도록 구성할 수 있습니다:

config.active_record.encryption.key_provider = ActiveRecord::Encryption::EnvelopeEncryptionKeyProvider.new

다른 내장 키 공급자와 마찬가지로 active_record.encryption.primary_key에 기본 키 목록을 제공하여 키 교체 체계를 구현할 수 있습니다.

사용자 지정 키 공급자

더 복잡한 키 관리 체계의 경우 초기화기에서 사용자 지정 키 공급자를 구성할 수 있습니다:

ActiveRecord::Encryption.key_provider = MyKeyProvider.new

키 공급자는 다음 인터페이스를 구현해야 합니다:

class MyKeyProvider
  def encryption_key
  end

  def decryption_keys(encrypted_message)
  end
end

두 메서드 모두 ActiveRecord::Encryption::Key 객체를 반환합니다:

  • encryption_key는 일부 내용을 암호화하는 데 사용되는 키를 반환합니다.
  • decryption keys는 주어진 메시지를 복호화할 수 있는 잠재적 키 목록을 반환합니다.

키에는 암호화된 메시지와 함께 저장되는 임의의 태그가 포함될 수 있습니다. ActiveRecord::Encryption::Message#headers를 사용하여 복호화할 때 이러한 값을 검사할 수 있습니다.

모델별 키 공급자

:key_provider 옵션을 사용하여 클래스별로 키 공급자를 구성할 수 있습니다:

class Article < ApplicationRecord
  encrypts :summary, key_provider: ArticleKeyProvider.new
end

모델별 키

:key 옵션을 사용하여 클래스별로 특정 키를 구성할 수 있습니다:

class Article < ApplicationRecord
  encrypts :summary, key: "some secret key for article summaries"
end

Active Record는 이 키를 사용하여 데이터를 암호화하고 복호화하는 데 사용되는 키를 파생시킵니다.

키 교체

active_record.encryption은 키 교체 체계를 구현하기 위해 키 목록으로 작동할 수 있습니다:

  • 마지막 키가 새 내용을 암호화하는 데 사용됩니다.
  • 하나라도 작동할 때까지 모든 키가 암호화된 내용을 복호화하는 데 시도됩니다.
active_record_encryption:
  primary_key:
    - a1cc4d7b9f420e40a337b9e68c5ecec6 # 이전 키는 기존 내용을 계속 복호화할 수 있습니다.
    - bc17e7b413fd4720716a7633027f8cc4 # 활성, 새 내용을 암호화합니다.네, 계속해서 번역하겠습니다.

```yml
  key_derivation_salt: a3226b97b3b2f8372d1fc6d497a0c0d3

이를 통해 새 키를 추가하고, 내용을 다시 암호화하고, 오래된 키를 삭제하는 워크플로를 통해 짧은 키 목록을 유지할 수 있습니다.

참고: 키 교체는 현재 결정론적 암호화에 지원되지 않습니다.

참고: Active Record 암호화는 아직 키 교체 프로세스의 자동 관리를 제공하지 않습니다. 모든 구성 요소가 있지만 아직 구현되지 않았습니다.

키 참조 저장

config.active_record.encryption.store_key_references를 구성하여 active_record.encryption이 암호화된 메시지에 암호화 키에 대한 참조를 저장하도록 할 수 있습니다.

config.active_record.encryption.store_key_references = true

이렇게 하면 시스템이 키 목록을 직접 찾을 수 있어 복호화 성능이 향상됩니다. 대신 저장 공간이 약간 늘어납니다.

API

기본 API

Active Record 암호화는 선언적으로 사용하도록 의도되었지만 고급 사용 시나리오를 위한 API를 제공합니다.

암호화 및 복호화

article.encrypt # 모든 암호화 가능한 속성 암호화 또는 재암호화
article.decrypt # 모든 암호화 가능한 속성 복호화

암호문 읽기

article.ciphertext_for(:title)

속성이 암호화되었는지 여부 확인

article.encrypted_attribute?(:title)

구성

구성 옵션

application.rb(가장 일반적인 시나리오) 또는 특정 환경 구성 파일 config/environments/<env name>.rb에서 Active Record 암호화 옵션을 구성할 수 있습니다(환경별로 설정하려는 경우).

경고: Rails 내장 자격 증명 지원을 사용하여 키를 저장하는 것이 좋습니다. 수동으로 구성 속성을 통해 설정하려는 경우 코드와 함께 커밋하지 않도록 주의하세요(예: 환경 변수 사용).

config.active_record.encryption.support_unencrypted_data

true이면 암호화되지 않은 데이터를 정상적으로 읽을 수 있습니다. false이면 오류가 발생합니다. 기본값: false.

config.active_record.encryption.extend_queries

true이면 결정론적으로 암호화된 속성을 참조하는 쿼리가 필요한 경우 추가 값을 포함하도록 수정됩니다. 이러한 추가 값에는 값의 일반 버전(config.active_record.encryption.support_unencrypted_data가 true인 경우) 및 이전 암호화 체계로 암호화된 값(제공된 경우 previous: 옵션)이 포함됩니다. 기본값: false(실험적).

config.active_record.encryption.encrypt_fixtures

true이면 픽스처의 암호화 가능한 속성이 자동으로 암호화됩니다. 기본값: false.

config.active_record.encryption.store_key_references

true이면 암호화된 메시지의 헤더에 암호화 키에 대한 참조가 저장됩니다. 이렇게 하면 여러 키를 사용할 때 복호화 속도가 빨라집니다. 기본값: false.

config.active_record.encryption.add_to_filter_parameters

true이면 암호화된 속성 이름이 자동으로 config.filter_parameters에 추가되어 로그에 표시되지 않습니다. 기본값: true.

config.active_record.encryption.excluded_from_filter_parameters

config.active_record.encryption.add_to_filter_parameters가 true일 때 필터링되지 않도록 할 매개변수 목록을 구성할 수 있습니다. 기본값: [].

config.active_record.encryption.validate_column_size

열 크기를 기반으로 유효성 검사를 추가합니다. 이렇게 하면 압축이 잘되는 페이로드를 사용하여 큰 값을 저장하는 것을 방지할 수 있습니다. 기본값: true.

config.active_record.encryption.primary_key

루트 데이터 암호화 키를 파생하는 데 사용되는 키 또는 키 목록입니다. 이는 active_record_encryption.primary_key 자격 증명을 통해 구성하는 것이 좋습니다.

config.active_record.encryption.deterministic_key

결정론적 암호화에 사용되는 키 또는 키 목록입니다. active_record_encryption.deterministic_key 자격 증명을 통해 구성하는 것이 좋습니다.

config.active_record.encryption.key_derivation_salt

키를 파생할 때 사용되는 솔트입니다. active_record_encryption.key_derivation_salt 자격 증명을 통해 구성하는 것이 좋습니다.

config.active_record.encryption.forced_encoding_for_deterministic_encryption

결정론적으로 암호화된 속성에 대한 기본 인코딩입니다. nil로 설정하면 강제 인코딩이 비활성화됩니다. 기본값은 Encoding::UTF_8입니다.

config.active_record.encryption.hash_digest_class

키를 파생하는 데 사용되는 다이제스트 알고리즘입니다. 기본값은 OpenSSL::Digest::SHA256입니다.

config.active_record.encryption.support_sha1_for_non_deterministic_encryption

SHA1 다이제스트 클래스를 사용하여 비결정론적으로 암호화된 데이터를 복호화할 수 있습니다. 기본값은 false이며, 이는 config.active_record.encryption.hash_digest_class에 구성된 다이제스트 알고리즘만 지원한다는 의미입니다.

암호화 컨텍스트

암호화 컨텍스트는 특정 시점에 사용되는 암호화 구성 요소를 정의합니다. 전역 구성을 기반으로 기본 암호화 컨텍스트가 있지만 특정 속성 또는 특정 코드 블록에 대해 사용자 지정 컨텍스트를 구성할 수 있습니다.

참고: 암호화 컨텍스트는 유연하지만 고급 구성 메커니즘입니다. 대부분의 사용자는 이에 대해 신경 쓰지 않아도 됩니다.

암호화 컨텍스트의 주요 구성 요소는 다음과 같습니다:

  • encryptor: 데이터를 암호화하고 복호화하는 내부 API를 노출합니다. key_provider와 상호 작용하여 암호화된 메시지를 구축하고 직렬화를 처리합니다. 암호화/복호화 자체는 cipher에 의해 수행되고 직렬화는 message_serializer에 의해 수행됩니다.
  • cipher: 실제 암호화 알고리즘(AES 256 GCM)
  • key_provider: 암호화 및 복호화 키를 제공합니다.
  • message_serializer: 암호화된 페이로드(Message)를 직렬화하고 역직렬화합니다.

참고: 사용자 지정 message_serializer를 빌드하는 경우 임의의 객체를 역직렬화할 수 없는 안전한 메커니즘을 사용해야 합니다. 일반적으로 지원되는 시나리오는 기존 암호화되지 않은 데이터 암호화입니다. 공격자는 이를 악용하여 암호화 전에 조작된 페이로드를 입력하고 RCE 공격을 수행할 수 있습니다. 따라서 사용자 지정 직렬화기는 Marshal, YAML.load(대신 YAML.safe_load 사용), JSON.load(대신 JSON.parse 사용)를 피해야 합니다.

전역 암호화 컨텍스트

전역 암호화 컨텍스트는 기본적으로 사용되는 것이며 application.rb 또는 환경 구성 파일에서 다른 구성 속성과 마찬가지로 구성됩니다.

config.active_record.encryption.key_provider = ActiveRecord::Encryption::EnvelopeEncryptionKeyProvider.new
config.active_record.encryption.encryptor = MyEncryptor.new

속성별 암호화 컨텍스트

속성 선언에서 암호화 컨텍스트 매개변수를 재정의할 수 있습니다:

class Attribute
  encrypts :title, encryptor: MyAttributeEncryptor.new
end

코드 블록 실행 시 암호화 컨텍스트

ActiveRecord::Encryption.with_encryption_context를 사용하여 특정 코드 블록에 대한 암호화 컨텍스트를 설정할 수 있습니다:

ActiveRecord::Encryption.with_encryption_context(encryptor: ActiveRecord::Encryption::NullEncryptor.new) do
  # ...
end

내장 암호화 컨텍스트

암호화 비활성화

암호화 없이 코드를 실행할 수 있습니다:

ActiveRecord::Encryption.without_encryption do
  # ...
end

이는 암호화된 텍스트를 읽으면 암호문이 반환되고 저장된 내용은 암호화되지 않음을 의미합니다.

암호화된 데이터 보호

암호화된 데이터는 보호하지만 암호화 없이 코드를 실행할 수 있습니다:

ActiveRecord::Encryption.protecting_encrypted_data do
  # ...
end

이는 Rails 콘솔에서 암호화된 데이터를 보호하면서 임의의 코드를 실행할 수 있는 경우에 유용할 수 있습니다.