暗号と鍵の管理

OWASP の Cryptographic Storage Cheat Sheet を取得して読み、 理解した内容を自分の言葉で書いたもの。

OWASP Top 10A04 Cryptographic Failures に対応する。 秘密情報の管理資格情報の置き場所の話なら、 こちらは暗号そのものの選び方と鍵のライフサイクル

大原則

自作しない。 原典の言い方も端的で、独自アルゴリズムについては「やるな」の一言。

十分に検証された確立されたライブラリを使う。

アルゴリズムの選択

共通鍵暗号

AES。鍵長は最低128ビット、256ビットが望ましい
規制要件(FIPS 140-2、PCI DSS など)がある場合はそれを満たす鍵長にする

モードの選択が本体。

優先度モード得られるもの
最優先GCM または CCM完全性・真正性・機密性のすべて(認証付き暗号)
次善CTR または CBC + 別途の認証Encrypt-then-MAC で完全性を足す
使わないECB極めて稀な状況を除いて使わない

認証なしの暗号化は、改ざんを検知できない。 「暗号化してあるから安全」が成り立つのは、認証付きモードを使っているときだけ。

公開鍵暗号

楕円曲線暗号(ECC)、Curve25519 を優先する
RSA を使う必要があるなら最低2048ビット
RSA には必ずランダムパディング(OAEP / PKCS#1)を有効にする

パディングが要るのは、既知平文攻撃への防御のため。

ハッシュとパスワード

パスワードは可逆な暗号化で保存しない。 安全なハッシュアルゴリズムを使う。

具体的なアルゴリズムは Password Storage Cheat Sheet に分離されている。 認証と認可も参照。

乱数

用途によって使い分ける。ここを間違えると暗号全体が無意味になる。

種類用途
PRNG(疑似乱数)速いがセキュリティ用途には使えない
CSPRNG(暗号論的に安全な疑似乱数)暗号鍵、IV、セッションID、CSRFトークン、パスワードリセットのトークン

言語ごとの安全な関数。

Java        SecureRandom
Python      secrets
Go          crypto/rand
Node.js     crypto.randomBytes()
PHP         random_bytes()
.NET        RandomNumberGenerator

Math.random()rand() の類をセッションIDに使わない、が最も頻出する誤り。

鍵の管理

データと鍵を分離する

暗号鍵は暗号化されたデータと別の場所に置く。 例えばデータはデータベース、鍵はファイルシステム。 理想は物理的に別のシステムへ分離すること。

同じデータベースに両方あるなら、そのデータベースが抜かれた時点で暗号化の意味がない。

2階層の鍵

DEK (Data Encryption Key)   実際のデータを暗号化する
KEK (Key Encryption Key)    DEK を暗号化する。別の場所に保管する

これでDEK のローテーションが、データ全体の再暗号化なしにできるようになる。

保管場所(安全な順)

1. HSM(ハードウェアセキュリティモジュール)または相当の仮想製品
2. クラウドの鍵管理サービス(AWS KMS、Azure Key Vault)
3. 外部の秘密情報管理(HashiCorp Vault、Conjur)
4. OS やフレームワークの API(.NET の ProtectedData など)
5. 権限を絞った設定ファイル(最後の手段)

避けるもの。

ソースコードへのハードコード
バージョン管理への格納
環境変数
  phpinfo() や /proc/self/environ から露出しうる

環境変数が「避ける」側に入っているのは見落としやすい。 秘密情報の管理で挙げた 「CI/CD が秘密情報に触れない」構成が、ここでも効く。

ローテーションの引き金

侵害の疑い、または確認
暗号利用期間(cryptoperiod)の満了。脅威モデルによる。NIST SP 800-57 を参照
データ量の閾値を超えたとき(64ビット鍵なら 2^35 バイト)
アルゴリズムの脆弱性が判明したとき

ローテーションの手順は、必要になる前にテストしておく。 緊急時に初めて実行するものにしない。

古い鍵は一時的に保持する。 過去のバックアップを復号する必要があるため。

何を暗号化するか

まず、機微なデータの保存自体を最小にする。 特にクレジットカード情報は PCI DSS の要求が厳しいので、持たない判断が最も効く。

暗号化が必要な場合は、脅威モデルに応じて層を選ぶ。

アプリケーション層 / データベース層 / ファイルシステム層 / ハードウェア層

URL パラメータの暗号化だけに頼らない。 アクセス制御を独立して強制する(認証と認可)。

既存の記述との対応

既にあるここでの位置づけ
秘密情報の管理 の AES-256-GCM 推奨認証付きモードの選択
同「鍵は暗号化されたデータと別の場所に保管する」データと鍵の分離
同 ローテーションの自動化ローテーションの引き金と手順
API 設計転送時の保護
認証と認可パスワードの保管

関連