大事なデータを守りたい!ActiveRecord Encryptionと、より安全かつ検索可能な暗号化手法の実装例の紹介

859 Views

October 26, 24

スライド概要

Kaigi on Rails Day2にて使用した発表用スライドです。

https://kaigionrails.org/2024/talks/f-world21/

シェア

またはPlayer版

埋め込む »CMSなどでJSが使えない場合

関連スライド

各ページのテキスト
1.

大事なデータを守りたい! ActiveRecord Encryptionと、 より安全かつ検索可能な 暗号化手法の実装例の紹介 2024.10.26(Sat.) Kaigi on Rails 2024 Day2@Hall Blue 小林悟史(noel) ブルーモ証券株式会社 ©2024 Bloomo Securities Inc.

2.

• 小林 悟史(小林 ノエル) @free_world21 • ブルーモ証券株式会社 取締役CTO • Omotesando.rb, Roppongi.rb, Shinjuku.rbとかによくいま す • 旅行・世界のコワーキングスペースめぐり(ワーケーション 的な何か)が好き • 趣味で【政治資金データベース】を開発してます 好きなバンド • LʼArc~en~Ciel, PIERROT THE FARM@NY ©2024 Bloomo Securities Inc. CARR WORKPLACE@Chicago

3.

Index 01 会社紹介&背景紹介 02 そもそも暗号化とは? 03 ActiveRecord Encryptionの紹介 04 ActiveRecord Encryptionでは実現しづらい要件の例 05 各種暗号化手法ご紹介 06 attr_encrypted を使った実装例 07 暗号化しつつ検索可能にする方法の紹介 08 まとめ • 話さないこと:暗号化アルゴリズムとか秘密計算・検索とか • 対象者:開発しているRailsアプリのデータ暗号化に興味がある人 • 目的:ActiveRecord Encryption, attr̲encrypted, lockboxの概要とつかいどころを理解すること • 発表資料は後ほど公開します ©2024 Bloomo Securities Inc.

4.

01 会社紹介&背景紹介 ‒ プロダクト 米国株資産運用アプリBloomoを提供中! コピペで「バフェット投資」 スマホ完結で若者も気軽に YOUTH FINANCE① ©2024 Bloomo Securities Inc.

5.

01 会社紹介&背景紹介 ‒ プロダクト機能 ポートフォリオ機能で、高度な資産運用のハードルを下げている ポートフォリオ投資機能 米国株・ETFで理想のポートフォリオを作成したら、 両替や買付はブルーモが自動執行してくれる。 複数銘柄への分散投資が手間なく実現できる (ユーザーの保有銘柄数は10以上(日本平均の3倍程度)) 共有・コピー機能 専門家や他のユーザーのポートフォリオを見て、 ワンタップでコピーできる。 初心者でもポートフォリオ作成が可能に (ユーザーの9割以上がコピーから開始) ©2024 Bloomo Securities Inc.

6.

01 会社紹介&背景紹介 ‒ 創業からこれまでの歩み 6年ぶりの証券会社スタートアップとして立ち上がった 個別株を取扱う証券会社スタートアップとしては、Finatext・FOLIO以来の存在。史上最速ペースで⾦商1種(証券会社) ライセンス取得・プロダクトリリースを続けてきた。 シードラウンド 8億円調達 2022 6月 創業 2023 4月 NISA口座 提供開始 招待制リリース 2023 6月 証券会社 ライセンス取得 2024 2月 2024 5月 2024 10月 正式リリース (一般公開) ©2024 Bloomo Securities Inc.

7.

01 会社紹介&背景紹介 ‒ 創業からこれまでの歩み 6年ぶりの証券会社スタートアップとして立ち上がった 証券会社としての rails new . 個別株を取扱う証券会社スタートアップとしては、Finatext・FOLIO以来の存在。史上最速ペースで⾦商1種(証券会社) ライセンス取得・プロダクトリリースを続けてきた。 シードラウンド 8億円調達 2022 6月 創業 2023 4月 NISA口座 提供開始 招待制リリース 2023 6月 証券会社 ライセンス取得 2024 2月 2024 5月 2024 10月 正式リリース (一般公開) ©2024 Bloomo Securities Inc.

8.

01 会社紹介&背景紹介 ‒ 創業からこれまでの歩み 6年ぶりの証券会社スタートアップとして立ち上がった 証券会社としての rails new . 個別株を取扱う証券会社スタートアップとしては、Finatext・FOLIO以来の存在。史上最速ペースで⾦商1種(証券会社) ライセンス取得・プロダクトリリースを続けてきた。 シードラウンド 8億円調達 2022 6月 創業 2023 4月 NISA口座 提供開始 招待制リリース 2023 6月 証券会社 ライセンス取得 2024 2月 2024 5月 2024 10月 正式リリース (一般公開) ©2024 Bloomo Securities Inc.

9.

01 会社紹介&背景紹介 ‒ 証券システムを作るうえで お客様(使う側)目線 • 何か株を買うためには証券会社の口座をつくらなければいけない エンジニア(作る側)目線 • 証券会社(のシステム)を作るためには様々な要件(法律など)を守らなければいけない • セキュリティー周りにもより気を使う必要がある • サイバー攻撃などを含む、情報セキュリティに関する脅威がものすごい勢いで強まっている – 相次ぐ個人情報流出 – ランサムウェアによる被害(ニコニコ動画) ©2024 Bloomo Securities Inc.

10.

02 そもそも暗号化とは? - 暗号化とハッシュ化 暗号化 • データを特定の暗号鍵を使って変換し、正しい鍵がないと元に戻せないようにする処理 • データの機密性を保護するために使われる “小林ノエル” 平文 🔑 “m6mlF70S3Qoqt86hyUJzWxhwW6JYgyXgBPPJHrhvVAGQ” 暗号文 ハッシュ化 • データを一方向の固定長の値に変換することで、元のデータに戻せないようにする処理 • 主にデータの整合性を確認するために使われる “小林ノエル” 元データ “$2a$10$aBy67z2lE8O/OO/Xfnr7ZO6sQCP948cWDM/9Mi fMGR5472nkfqGUW” ハッシュ値 ©2024 Bloomo Securities Inc.

11.

02 そもそも暗号化とは? - なぜ暗号化するのか • 入口対策・内部対策・出口対策のうち、内部対策のうちの1つ – 入口対策 • ファイアウォール・フィルター • 多要素認証、VPNなど – 内部対策 • データ暗号化 • ログ監視 – 出口対策 • • 通信できる経路を絞る • 外部デバイスへのデータ書き込み制限 何かデータが流出したときの被害を抑えるための手法 ©2024 Bloomo Securities Inc.

12.

02 そもそも暗号化とは ‒ 暗号化をする際に考慮すべきポイント • 暗号化のアルゴリズム – DES, AES, RSA, ECC, … – ほとんどの場合フレームワークやライブラリのデフォルト(推奨)のものを使えばOK • 本日のお話のスコープ外 • 鍵の管理方針 鍵の管理方針 – 暗号鍵をどこにおいて誰が管理するのか? • 暗号化の単位 暗号化の単位 – どのような単位で暗号化するか • • • • アプリケーションすべてを1つの鍵で一括暗号化 ある程度まとまった単位(テーブルごととか)で暗号鍵をわける レコードごとに暗号鍵をわける 検索性能 検索性能 – 暗号化したデータを DB に入れると多くの場合で検索ができなくなる – 必要に応じてアプリケーションレイヤで検索機能を実装する必要がある ©2024 Bloomo Securities Inc.

13.

03 ActiveRecord Encryptionの紹介 ‒ 概要 • Rails(ActiveRecord) に組み込まれている暗号化機構 – DBに保存するときに暗号化されて保存される – アプリケーション層:平文として扱える、DB層:暗号文として保存される $ rails db:encryption:init Add this entry to the credentials of the target environment: active_record_encryption: primary_key: azc7QkZYSg9ll01TjBNpnURUnF42gt1s deterministic_key: U987a4KAnhfA5oAQrLY7pYaTqysIYqqE key_derivation_salt: puoi8lJbvyM4FQErFYJ26BFuE1OJLHtf config/credentials.yml.enc にそのままコピペ secret_key_base: hogehogefugafuga…… active_record_encryption: primary_key: azc7QkZYSg9ll01TjBNpnURUnF42gt1s deterministic_key: U987a4KAnhfA5oAQrLY7pYaTqysIYqqE key_derivation_salt: puoi8lJbvyM4FQErFYJ26BFuE1OJLHtf ©2024 Bloomo Securities Inc.

14.

03 ActiveRecord Encryptionの紹介 ‒ 概要 • Rails(ActiveRecord) に組み込まれている暗号化機構 – DBに保存するときに暗号化されて保存される – アプリケーション層:平文として扱える、DB層:暗号文として保存される class PersonalInfo < ApplicationRecord encrypts :first_name encrypts :last_name end ©2024 Bloomo Securities Inc.

15.

03 ActiveRecord Encryptionの紹介 ‒ 概要 • 暗号鍵は属性ごとに文字列やカスタムキープロバイダを指定可能 class PersonalInfo < ApplicationRecord encrypts :first_name, key: "some secret key for personal_info" encrypts :last_name, key_provider: PersonalInfoKeyProvider.new end • 決定論的暗号化を使えば検索も可能 class PersonalInfo < ApplicationRecord encrypts :first_name, deterministic: true encrypts :last_name, deterministic: true end ©2024 Bloomo Securities Inc.

16.

03 ActiveRecord Encryptionの紹介 ‒ 概要 • 鍵の管理方針 鍵の管理方針 – config/credentials.yml.enc に記載 – カスタムキープロバイダを使えばプログラム的に取得可能(例:KMS, SecretManager 等) • 暗号化の単位 暗号化の単位 – デフォルトでは単一の鍵ですべての対象データを暗号化 – カスタムキープロバイダを使えば、クラス(テーブル)ごとに分けることも可能 • 検索性能 検索性能 – デフォルトでは非決定論的暗号化(検索不可能) – 決定論的暗号化モードにすれば検索可能 ©2024 Bloomo Securities Inc.

17.

04 ActiveRecord Encryptionでは実現しづらい要件 ‒ 金融機関を例に • 鍵の管理方針 鍵の管理方針 – 人間が管理したくない – (ここは ActiveRecord Encryption でも実現できる) • • 暗号化の単位 暗号化の単位 – 会社そのものの性質&扱うデータの重要性から、レコードごとに異なる暗号鍵を使いたい • 個人情報 • マイナンバー(一時的) • 本人確認書類画像(免許証など) • (クレジットカード番号) 検索性能 検索性能 – お客様からの問い合わせがあったときに、本人確認のために一定項目での検索は必要 • 名前と生年月日 • 住所 ©2024 Bloomo Securities Inc.

18.

05 各種暗号化手法ご紹介 ‒ attr_encrypted と lockbox attr_enctypted • Rails ✕ 暗号化では一番歴史が古い – ActiveRecord Encryption以前からある – First release: 2009/01 • 多くの参考文献がある • 小林自身が昔から使ってた経験がある lockbox • attr_encrypted の現代版的な位置づけ • 使い方はActiveRecord Encryptionやattr_encryptedとだいたい同じ • ActiveRecord Encryptionより少しだけ前に初期リリース – ActiveRecord Encryption (Rails 7.0): 2021/09 – lockbox first release: 2019/01 ©2024 Bloomo Securities Inc.

19.

06 attr_encrypted を使った実装例 ‒ 暗号鍵の管理方針のオプション 1. 環境変数に平文の暗号鍵を置く – 一番シンプルで簡単だが脆弱 2. Secret Manager などアプリケーションサーバの外に平文の暗号鍵を置く – 👆よりは安全だが依然として人間が管理する必要がある 3. Rails の Encypted Credentials を使う – credentials.yml.enc を複合する鍵(master.key)をどうするかという問題は顕在 – やっぱり人間が管理する必要がある 4. Key Management Serivceをつかう – AWS, GCP, Azure など、クラウドプロバイダなら基本的には提供してる ©2024 Bloomo Securities Inc.

20.

06 attr_encrypted を使った実装例 ‒ Key Management Service とは(AWSを例に) • Customer Master Key(CMK)を指定して、data key(新しい暗号鍵)を要求する – CMK A has_many :data_keys • 以下のものがKMSから返ってくる – A: 平文の暗号鍵 – B: Aが暗号化されたもの • 暗号化:Aで暗号化して、それは消去。BをDBなどに保存しておく。 • 復号化:BをKMSに投げつけると復号化して返してくれる(Aを得られる)ので、データ本体 をAで復号化する ©2024 Bloomo Securities Inc.

21.

06 attr_encrypted を使った実装例 ‒ KMSを使ったレコードごとの暗号化実装例 1. KMSから取得した【暗号化された暗号鍵(B)】を保存するためのカラム encrypted_data_key を暗号化対象クラス(テーブル)に追加 2. 下記のようなメソッドをもつ module を定義 module KmsKey def data_key kms_client = Aws::KMS::Client.new(region: aws_region) if self.encrypted_data_key kms_client.decrypt(ciphertext_blob: self.encrypted_data_key) else resp = kms_client.generate_data_key( key_id: Rails.application.config.x.common['kms_cmk_id’], key_spec: 'AES_256’, ) self.encrypted_data_key = resp.ciphertext_blob resp.plaintext end end ©2024 Bloomo Securities Inc.

22.

06 attr_encrypted を使った実装例 ‒ KMSを使ったレコードごとの暗号化実装例 3. 暗号化対象フィールドを定義 class PersonalInfo < ApplicationRecord include KmsKey attr_encrypted :first_name, key: :data_key, algorithm: 'aes-256-gcm’ attr_encrypted :last_name, key: :data_key, algorithm: 'aes-256-gcm' ©2024 Bloomo Securities Inc.

23.

06 attr_encrypted を使った実装例 ‒ KMSを使ったレコードごとの暗号化実装例 4. レコードごとに暗号鍵を変えつつ、透過的に扱えるようになる personal_info.first_name = ”ノエル” personal_info.last_name = “小林” personal_info.save! personal_info = PersonalInfo.find(1) puts personal_info.first_name # => “ノエル” puts personal_info.last_name # => “小林” ©2024 Bloomo Securities Inc.

24.

06 attr_encrypted を使った実装例 ‒ アップロード画像の暗号化 • carrierwaveを例にご紹介 • レコードごとに暗号鍵を変えつつ、アップロード画像そのものも暗号化して保存 class IdDocumentImage < ApplicationRecord include KmsKey mount_uploader :uploader, IdDocumentImageUploader before_save :encrypt_file! def encrypt_file! iv = Cipher.generate_iv self.uploader_iv = Base64.strict_encode64(iv) cipher = Cipher.new(key: data_key, cipher_iv: iv) resp = cipher.encrypt(value: uploader.file.read) File.binwrite(uploader.file.path, resp) end ©2024 Bloomo Securities Inc.

25.

07 暗号化しつつ検索可能にする方法の紹介 ‒ 暗号化しつつ検索可能にするオプション 1. 決定論的暗号化を使う – ActiveRecord Encryption が採用している方針 – 同じ暗号化鍵で暗号化しているデータ郡に対しては可能な手法 2. ElasticSearch などの検索モジュールを用意し、そこに平文のデータを格納する – ElasticSearch はアプリケーションサーバからのみアクセス可能で、経路や領域は安全と いう前提 3. 検索時はアプリケーションサーバ内で一括複合して、コード上で検索する – PersonalInfo.all.each みたいにするイメージ 4. 検索用に対象フィールド(氏名、住所など)のハッシュ値を別テーブルに保存する – 完全一致の検索のみ可能 ©2024 Bloomo Securities Inc.

26.

07 暗号化しつつ検索可能にする方法の紹介 ‒ 暗号化対象データを保存しつつ検索用Hashを作成する例 • PersonalInfoHash モデル(テーブル)を定義 – key: string – value: string class PersonalInfoHash < ApplicationRecord belongs_to :personal_info end class PersonalInfo < ApplicationRecord include KmsKey …… has_many :personal_info_hashes ©2024 Bloomo Securities Inc.

27.

07 暗号化しつつ検索可能にする方法の紹介 ‒ 暗号化対象データを保存しつつ検索用Hashを作成する例 • after_save とかで PersonalInfo のレコードと一緒に作る • 暗号学的Hash関数はとりあえず Bcrypt 使っておけば良さそう class PersonalInfo < ApplicationRecord after_save :save_hashes def save_hashes save_name_hash save_tel_hash ... end def save_name_hash raw_value = last_name + first_name pi_hash = personal_info_hashes.find_or_initialize_by(key: 'last_name_and_first_name’) pi_hash.value = BCrypt::Engine.hash_secret(raw_value, ENV['HASH_SALT’]) pi_hash.save! end ©2024 Bloomo Securities Inc.

28.

07 暗号化しつつ検索可能にする方法の紹介 ‒ 暗号化対象データを保存しつつ検索用Hashを作成する例 • 検索するときは検索ワードのハッシュ値を計算して検索 hash_value = BCrypt::Engine.hash_secret(searching_value, ENV['HASH_SALT’]) personal_infos = PersonalInfoHash .where(key: 'last_name_and_first_name', hash_value: hash_value) .map(&:personal_info) ©2024 Bloomo Securities Inc.

29.

08 まとめ • 今回ご紹介した方法を特性ごとにまとめます ActiveRecord Encryption attr_encrypted lockbox 初期リリース Rails 7.0 (2021/09) 2009/01 2019/01 提供元 built-in gem gem 暗号化の 単位 一括暗号化 暗号鍵の 管理 環境変数 Secret Manager credentilas.yml.enc KMS 検索手法 決定論的暗号化による検索 Elastic Search 愚直検索 ハッシュ化による検索 デフォルトの使い方 テーブルごとに暗号化 レコードごとに暗号化 カスタマイズすればできる ©2024 Bloomo Securities Inc.

30.

08 まとめ ‒ ActiveRecord Encryption • 大抵の要件は満たせる • 導入の敷居も低い – config.active_record.encryption.support_unencrypted_data = true ActiveRecord Encryption attr_encrypted lockbox 初期リリース Rails 7.0 (2021/09) 2009/01 2019/01 提供元 built-in gem gem 暗号化の 単位 一括暗号化 暗号鍵の 管理 環境変数 Secret Manager credentilas.yml.enc KMS 検索手法 決定論的暗号化による検索 Elastic Search 愚直検索 ハッシュ化による検索 デフォルトの使い方 テーブルごとに暗号化 レコードごとに暗号化 カスタマイズすればできる ©2024 Bloomo Securities Inc.

31.

08 まとめ ‒ attr̲encrypted & lockbox • ActiveRecord Encryptionで要件が満たせない場合(レコードごと暗号化など)に検討 • KMS利用 (kms_encrypted)、ハッシュ化検索 (blind_index) は別の gem がある • 新規案件なら lockbox、既存コードを使いまわしたい場合は attr_encrypted ActiveRecord Encryption attr_encrypted lockbox 初期リリース Rails 7.0 (2021/09) 2009/01 2019/01 提供元 built-in gem gem 暗号化の 単位 一括暗号化 暗号鍵の 管理 環境変数 Secret Manager credentilas.yml.enc KMS 検索手法 決定論的暗号化による検索 Elastic Search 愚直検索 ハッシュ化による検索 デフォルトの使い方 テーブルごとに暗号化 レコードごとに暗号化 カスタマイズすればできる ©2024 Bloomo Securities Inc.

32.

We are Hiring! 一緒にBloomoのサービス開発を してくれる仲間を募集中! https://careers.bloomo.co.jp/ ©2024 Bloomo Securities Inc.