Railsのsecret_key_baseを理解する(翻訳)
secret_key_base
の値の意味や、Railsアプリでの使われ方を知りたいと思ったことはありませんか。この設定値はRails 4から導入され、developmentやproductionといった環境ごとに定義されるのが普通ですが、値の目的はシンプルです。すなわち、値はアプリのkey_generator
メソッドのsecret入力として使われます。
このメソッドはRails.application.key_generator
でアクセスでき、引数を取らず、ActiveSupport::CachingKeyGenerator
インスタンスをひとつ返します。続いて、CachingKeyGenerator
クラスが提供するgenerate_key
メソッドを使ってキーを導出します。secret_key_base
は、さまざまなセキュリティ機能で個別のキーを引き続き使えるようにしつつ、開発者が(訳注: 個別のキーを)設定する負荷を軽減する役割を持っています。
CachingKeyGenerator
クラスは特にActiveSupport::KeyGenerator
クラスをラップします。このクラスは名前のとおり、導出したキーを内部のハッシュにキャッシュして保存します。ハッシュのエントリはsalt入力によってインデックス化されます(gist: rails_app_key_generator.rb: リンク切れ)。
# rails_app_key_generator.rb
# アプリのkey_generatorからキーを求める
# 戻り値: #<ActiveSupport::CachingKeyGenerator:0x00000004ae1b00 @key_generator=#<ActiveSupport::KeyGenerator:0x00000004ae1b28 @secret="...", @iterations=1000>, @cache_keys=#<Concurrent::Map:0x00000004ae1ad8 entries=0 default_proc=nil>>
Rails.application.key_generator
# 戻り値: "\a\xDD|\xEB\xE2\xD3\xEC\x05\xCA@C\xFBVD\xFB\xE5\x93o\e(\xDA\x83\x95}\xD3\x15\x91V\xA5y&6"
Rails.application.key_generator.generate_key('salt input', 32)
アプリのkey_generator
とsecret_key_base
は、Railsフレームワーク内の3つのコア機能で利用されます。
- 暗号化cookieで使うキーの導出:
coookies.encrypted
でアクセス可能 - HMAC署名されたcookieで使うキーの導出:
cookies.encrypted
でアクセス可能 - アプリのすべての名前付き
message_verifier
インスタンスで使うキーの導出
1. 暗号化cookie
このcookieは、暗号化によってコンテンツに完全性と機密性を提供します。Railsのセッションcookieは完全性と機密性のために暗号化cookieからビルドされます。
暗号化方式に応じて、secret_key_base
から1つまたは2つのキーが生成されます。
GCM暗号化方式が使われると、config.action_dispatch.authenticated_encrypted_cookie_salt
で定義されたsaltを使ってキーが1つ生成されます。このデフォルト値は"authenticated encrypted cookie"
です。
参考: Wikipedia-ja: Galois/Counter Mode (GCM)
CBC暗号化方式が使われると、キーが2つ導出されます。AESアルゴリズムをCBCモードで使っているので、メッセージはMACによる認証(authenticate)も必要です(リンク切れ)。
暗号化キーとベリファイキーは、定義されたsaltを用いて導出されます。
config.action_dispatch.encrypted_cookie_salt
(デフォルト値:"encrypted cookie"
)config.action_dispatch.encrypted_signed_cookie_salt
(デフォルト値:"signed encrypted cookie"
)
参考: Wikipedia-ja: CBCモード (Cipher Block Chaining Mode)
参考: Wikipedia-ja: メッセージ認証コード(MAC: Message Authentication Code)
2. 署名済みcookie
署名済みcookieは、HMACとSHA1ハッシュ関数を用いたセキュリティによってコンテンツに完全性を提供します。署名済みcookieの実装は暗号化cookieの実装に似ており、secret_base_key
から導出したキーを1つ使います。
署名済みcookieで使うキーを導出するときは、config.action_dispatch.signed_cookie_salt
で定義された設定値がsaltに使われます。デフォルト値は"signed cookie"
です。
3. アプリのmessage_verifier
Railsフレームワークでsecret_key_base
が使われる最後の場所は、アプリのmessage_verifier
メソッドであり、これもRails.application
でアクセス可能です。アプリのkey_generator
メソッドの場合と同様に、このメソッドもverifier_name
のみを引数として取り、引数はインデックス化に使われてMessageVerifier
インスタンスに保存されます。この引数は、secret_base_base
からキーを1つ導出する際のsalt入力としても用いられます(gist: rails_app_message_verifier.rb: リンク切れ)。
# rails_app_message_verifier.rb
# 戻り値: #<ActiveSupport::MessageVerifier:0x00000003f4b430 @secret="...", @digest="SHA1", @serializer=Marshal>
Rails.application.message_verifier('bins')
# 戻り値: "BAh7BjoNdmVyaWZpZWRJIgp2YWx1ZQY6BkVU--9c516b0cc3bfcfd759550181541a24ca1294507e"
signed_msg = Rails.application.message_verifier('bins').generate({ verified: 'value' })
# 戻り値: {:verified=>"value"}
Rails.application.message_verifier('bins').verify(signed_msg)
# ActiveSupport::MessageVerifier::InvalidSignature をraiseする
Rails.application.message_verifier('bins').verify("unknown msg")
アプリのmessage_verifier
メソッドは、メッセージ完全性機能のための簡単で便利なセキュリティAPIを提供し、いわゆる「remember me」トークンの実装や、署名済みURLによるリソースアクセス制御によく用いられます。このメソッドは、Rails 5.2で新しく導入されたActive Storageの機能でも使われています。
ActiveSupport::KeyGenerator
について
ActiveSupport::KeyGenerator
は、PBKDF2というKDF(鍵導出関数)の単なるラッパーです。このKDFのキー導出がパスワードベースであることを考えると、実際には最善のオプションではありません。特に、PBKDF2は人間が作ったパスフレーズを元に、キーのストレッチングと呼ばれるテクニックを反復的に使ってより強力なキーを生成する設計になっています。現実のRailsアプリで用いられるsecret_key_base
値には、SecureRandom
とrake secrets
でランダム生成されるセキュアな数値が使われるのが普通なので、人間が作ったパスフレーズよりも既に十分セキュアかつランダムな値になります。
実際には多くのRailsアプリで64バイト長のsecret_key_base
値が使われているので、PBKDF2でキーを導出すると、キーから導出される実際の出力の長さは20バイト(160ビット)に限定されます。Rails全体にわたって導出されるキーには、HKDF(HMAC-based Key Derivation Function)を使う方がより適切のようです。HKDFでは「抽出の後拡大(extract-then-expand)」アプローチを採用しているので、より長いキーを生成できるようになります。
次回
私はRailsでのHKDF実装の検討を開始しました。この機能を改善できたらプルリクを作成するつもりです。今後にご期待ください。
概要
原著者の許諾を得て翻訳・公開いたします。
参考: §3.2.55
config.secret_key_base
-- Rails アプリケーションの設定項目 - Railsガイド