Slide 1

Slide 1 text

セキュアなRAILSア プリを⽬指す Part2: 暗号化編(鍵の管理) 2019/05/29 Ebisu.rb

Slide 2

Slide 2 text

■ ⼩林 悟史(35) ■ 本業: 乞⾷(主にポイント、携帯電話) ■ 副業: プログラマ ■ 2008: フリーランスエンジニアとして独⽴ – flash/C#/rails/iOS/Androidなどなど ■ 2009: ⼤学院修了(情報理⼯学修⼠) ■ 2009: IPA未踏事業に採択される ■ 2016: エメラダ株式会社に三⾓ ■ 2018: 同社執⾏役員 ■ 2019: フリーランス&会社員として活動中 @f_world21

Slide 3

Slide 3 text

エメラダ株式会社 ■ ⾦融分野で3業種の登録済み – 第⼀種少額電⼦募集取扱業者(⾦融商品取引業者) – 貸⾦業者 – 電⼦決済等代⾏業(2号) ■ たくさんの法律を守らないといけない・・・ – ⾦融商品取引法 – 貸⾦業法 – 銀⾏法 – 個⼈情報保護法 – 犯罪による収益の移転防⽌に関する法律(犯収法) – 業界団体の規則・規定 ■ セキュリティまわりにめっちゃ気を使わないといけない・・・

Slide 4

Slide 4 text

なぜ暗号化をするのか ■ ⼊⼝対策・内部対策・外部対策のうち、内部対策のうちの1つ ■ ⼊⼝対策 – ファイアウォール ■ 内部対策 – 暗号化 – 詳細なログをとる ■ 外部対策 – 通信できる経路を絞る(特定のサーバへのみデータ送信可能、みたいな)

Slide 5

Slide 5 text

暗号化をする際に考慮すべきポイント ■ 検索性能 – 暗号化したデータをDBに⼊れるとSQLによる検索はできない – アプリケーションレイヤでの検索機能を実装する必要がある ■ 鍵の管理⽅針 – 暗号鍵をどこにおくべきか ■ 暗号化の単位 – どのような単位で暗号化するか

Slide 6

Slide 6 text

暗号化されたデータの検索機能の実装例 ■ ElasticSearchなどの検索モジュールを⽤意し、そこに平⽂のデータを格納する – ElasticSearchはアプリケーションサーバからのみアクセス可能で、経路は 安全という前提 ■ 検索⽤に各フィールド(⽒名、住所など)のハッシュ値を別テーブルに保存す る – 完全⼀致の検索のみ可能 ■ 検索時はアプリケーションサーバ内で⼀括複合して、rubyのコード上で検索す る – PersonalInfo.all.eachみたいにするイメージ

Slide 7

Slide 7 text

鍵の管理⽅針の例 ■ 環境変数に平⽂の鍵をおく ■ S3など、アプリケーションサーバの外に平⽂の鍵をおく – 取得経路は安全という前提 ■ RailsのEncrypted Credentialsを使う – Credentials.yml.encを複合する鍵をどうするかという問題は健在 ■ Key Management Serviceをつかう – AWS, GCP, Azureもあった気がする

Slide 8

Slide 8 text

暗号化の単位の例 ■ すべてのデータを1つの暗号鍵で取り扱う ■ ある程度まとまった単位(テーブル単位)ごとに暗号鍵を⽤意する ■ 1レコードにつき1つの暗号鍵を⽤意する ■ 単位を細かくすればするほど – 鍵の流出があっても、盗まれる情報を抑えることができるし、鍵の 交換コストも抑えられる – ⼀括複合するには多くのIOや計算⼒が必要なので、効率的なアルゴ リズム(並列化など)が必要

Slide 9

Slide 9 text

要件や仕様、ビジネス環境に応じて柔軟に ■ これらの⽅針は情報の重要性に応じて適宜変えるべき – 【情報資産管理規定】などがあればそれに従う ■ たとえば個⼈情報などは⼀般的には最重要な情報資産 – 1レコードにつき1鍵 – 平分のデータは絶対に持たないマン – あいまい検索は許しませんとビジネスサイドに強く⾔う⼼が必要 ■ その他のデータはある程度まとまった単位で暗号化する

Slide 10

Slide 10 text

Railsでの実装例

Slide 11

Slide 11 text

愚直に実装するとこんなかんじ personal_info = PersonalInfo.new personal_info.encrypted_first_name = encrypt(”悟史”, key) personal_info.encrypted_last_name = encrypt(“⼩林”, key) personal_info.save! pi = PersonalInfo.find(1) pi.first_name = decrypt(pi.encrypted_first_name, key) pi.last_name = decrypt(pi.encrypted_last_name, key) puts personal_info.first_name # => “悟史” puts personal_info.last_name # => “⼩林”

Slide 12

Slide 12 text

透過的に扱いたい︕ ■ attr_encrypted というgemが便利だった ■ 各modelのattributeを透過的に扱える 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 # => “⼩林”

Slide 13

Slide 13 text

AWS KMSについて ■ Customer Master Key(CMK)を指定して、data key(新しい暗号鍵)を要求す る – A ■ 以下のものがKMSから返ってくる – A: 平⽂の暗号鍵 – B: 上記の鍵が暗号化されたもの ■ Aで暗号化して、それは消去。BをDBなどに保存しておく。 ■ BをKMSに投げつけると復号化して返してくれる(Aを得られる)ので、データ 本体をAで復号化する CMK has_many :data_keys

Slide 14

Slide 14 text

たとえばこんなメソッドを⽤意する def data_key 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

Slide 15

Slide 15 text

demo

Slide 16

Slide 16 text

まとめ ■ 暗号化は仕様や要件に応じて、⽤法⽤量をまもってただしく使いましょう ■ AWS KMSを使ってrailsで暗号化されたデータを扱うしくみを紹介しました ■ 次回・・・ – 暗号化編(検索機能) – DBロック – Rubyでbinaryパースする話 https://github.com/f-world21/encryption_sample