2021年10月4日月曜日

Ruby で復号化可能なパスワードの管理方法を考える

Ruby で復号化可能なパスワードの管理方法を考える

概要

コード上でパスワードなどの認証情報を使って外部にアクセスしたい場合があります
もし認証情報が暗号化されている場合は何かしらの方法を使って復号化する処理をコード上に記載する必要があります

今回は ActiveSupport::MessageEncryptor を使って暗号化/復号化された認証情報を扱う方法を紹介します

また復号化の際に重要な復号化キーの管理方法も考えます

環境

  • macOS 11.6
  • Ruby 3.0.2p107
  • activesupport 6.1.4.1

準備

  • bundle init
  • vim Gemfile
gem "activesupport"
  • bundle install

暗号化されたパスワードを生成する

まずは暗号化されたパスワードを生成します

require 'active_support'

key = "sk123456789012345678901234567890" # key must be 32 bytes
crypt = ActiveSupport::MessageEncryptor.new(key)
encrypted_pwd = crypt.encrypt_and_sign("hoge")

これを実行すると TTFaaENWcmdJTTAwSUpuN2g5QWwrZz09LS1yQWw3Ymt3bkdXR3lmc2I3VWNhdWFBPT0=--194ef2156f114d9d1154cdd22dfedc31d5144017 という暗号化されたパスワード情報を取得できます

この暗号化されたパスワードをデータベースなりコンフィグファイルなりコード上で管理しているとします

復号化する処理の部分

では今度は復号化する処理を考えます 基本的には以下で OK です

require 'active_support'

key = "sk123456789012345678901234567890" # key must be 32 bytes
crypt = ActiveSupport::MessageEncryptor.new(key)
encrypted_pwd = "TTFaaENWcmdJTTAwSUpuN2g5QWwrZz09LS1yQWw3Ymt3bkdXR3lmc2I3VWNhdWFBPT0=--194ef2156f114d9d1154cdd22dfedc31d5144017"

raw_password = crypt.decrypt_and_verify(encrypted_pwd)

復号化する場合には decrypt_and_verify を使います
これで元のパスワードを取得できます

大事なのは 32バイトのキー情報

もうわかるかと思いますが暗号化するキーと復号化するキーはどちらも同じものを使っています

上記のサンプルでは直接コード上に key を記載していますがこれではダメです
データベースなどにある暗号化されたパスワードが漏洩しただけであれば key がわからない限りパスワードは元に戻せませんがもしコードが見れる場合には key がわかってしまうので簡単に復号化できてしまいます

なので key はまた別の場所で管理するようにしましょう
例えば暗号化されたパスワードがあるデータベースでもなくコードが管理されているリポジトリでもない第三のリポジトリを使ってそこで管理する方法です

この場合であればデータベースとコードが見れる状態であっても第三のリポジトリにアクセスできないのであればパスワードの復号化は防げます

ただコード自体は第三のリポジトリで管理されている key が必ず必要になるのでコードがデプロイされているサーバなどに入れてしまうのであれば復号化を防ぐ手段はありません

暗号化キーと復号化キーを更に分ける方法を考える

今回の ActiveSupport::MessageEncryptor ではできませんが暗号化するキーと復号化キーするキーを分けることでもう少しセキュリティを強化することができます

暗号化キーと復号化キーをそれぞれ別のリポジトリで管理することで堅牢にすることはできますがこの方法も結局コードがデプロイされているサーバにログインされてしまえばどちらも見ることができるはずなので微妙な感じにはなります

あとは復号化キーは別のデータベースで管理するという方法もあります

キーを外部から取得する

コード上では必要ですが処理が終了したら必ずキーを削除するようにします

そして再度複合化が必要な場合にはリポジトリや API を使って外部からキー情報を取得して復号化します

こうすればサーバ上に複合化キーの情報は残らないのでサーバにログインされても多少はキーの漏洩を防ぐことができます

bcrypt を使う

そもそも復号化の必要がないような仕組みにするのもありだと思います

ただ外部アクセスするようなケースだと bcrypt を使うのは難しいかもしれません

最後に

すべてのケースを想定した堅牢なパスワード管理を考えるのは不可能な気もします

しかしサーバにログインされたりデータベースにアクセスできたりと局所的になケースであればキーなどの情報を別の場所に保存するなりの対処で漏洩は防げる可能性は増えるかもしれません

最低でも復号化キー情報などはコードに直接書かずに外部で保存するようにしたほうがいいかなと思います

参考サイト

0 件のコメント:

コメントを投稿