VillageSQL is a drop-in replacement for MySQL with extensions.
All examples on this page work on VillageSQL. Install Now →
MD5() と SHA2() があります。開発者はパスワードをハッシュするときにこれらに手を伸ばします。それは間違いです。これらの関数は高速になるように設計されていますが、それはパスワードの保存にとってはまさに誤った性質です。
高速なハッシュがパスワードに不向きな理由
MD5 や SHA-256 のような暗号学的ハッシュ関数は速度に最適化されています。現代の GPU は毎秒数十億の SHA-256 ハッシュを計算できます。チェックサムやデータ整合性にはそれが役立ちます。パスワードにとっては、ハッシュ化されたパスワードのテーブルを入手した攻撃者が数時間でブルートフォースできることを意味します。 パスワードハッシュのアルゴリズム (bcrypt、Argon2、PBKDF2) は意図的に遅く作られています。1 つのパスワードの検証に数十ミリ秒かかるように設計されており、ログインには問題ありませんが、ブルートフォース攻撃は現実的でなくなります。標準的な答え: アプリケーションコードでハッシュする
ほとんどの MySQL アプリケーションは、アプリケーション層でハッシュすることでこれを正しく処理しています。PHP、Python、Node.js、あるいはアプリを動かしている言語が何であれ、そのbcrypt を使います。データベースはハッシュ化された値しか見ません。
これは機能しますが、分断を生みます。ハッシュのロジックはアプリケーションコードにあり、データはデータベースにあります。マイグレーション、一括操作、データのインポートは、正しくハッシュするためにアプリケーションを経由しなければならないか、複数のコードベースにハッシュのロジックを複製しなければなりません。
VillageSQL の場合: SQL で直接 PBKDF2
VillageSQL のvsql_crypto 拡張機能は crypt() と gen_salt() を追加します。PostgreSQL の pgcrypto をモデルにした、PBKDF2 ベースのパスワードハッシュ API です。アプリケーションコードを経由せずに、SQL でパスワードをハッシュし検証できます。
パスワードの保存
gen_salt は PBKDF2 ファミリーのみを扱います。pbkdf2-sha256 と pbkdf2-sha512、および短いエイリアスの pbkdf2、sha256、sha512 です。pgcrypto の bf (bcrypt)、md5、des の型はサポートされていません。gen_salt はそれらの名前に対して NULL を返します。
パスワードの検証
crypt() は保存されたハッシュからソルトとパラメータを自動的に取り出します。保存されたハッシュを 2 番目の引数として渡します。
反復回数の選択
反復回数は、ハッシュの計算にかかる時間を制御します。反復が多いほど遅くなり、ブルートフォースが難しくなりますが、ログインも遅くなります。
10,000 から始め、ハードウェアが許す限り増やしてください。ログインエンドポイントは 100ms を許容できます。数十億回の推測を試みる攻撃者には許容できません。
SQL でハッシュすべきときとアプリケーションコードでハッシュすべきとき
SQL でのハッシュが常に正しい選択とは限りません。次の場合に使ってください。- アプリを経由するのが現実的でない一括挿入やマイグレーションを行っている
- ハッシュのロジックをデータベース層に集中させたい
- SQL 駆動の管理ツールやシードスクリプトを構築している
- アプリケーションフレームワークに、十分にテストされた bcrypt/Argon2 ライブラリがすでにある
- 暗号のエコシステムが成熟した言語を使っている (ほとんどはそうです)
- スキーママイグレーションなしでハッシュアルゴリズムを入れ替えたい
よくある質問
PBKDF2 は bcrypt と同じくらい強力ですか?
同等の反復回数では、bcrypt がメモリハードである (GPU で並列化しにくい) ため、わずかに優位です。高い反復回数 (100,000 以上) の PBKDF2 は今も強力で、広く導入されています。この差は敵対的なシナリオでは重要ですが、どちらも SHA2 よりはるかに優れています。既存の SHA2 ハッシュを移行できますか?
はい。needs_rehash フラグを追加してください。ログインに成功したときに、ハッシュが古い SHA2 形式かどうかを確認し、crypt() で再ハッシュします。すべてのアクティブユーザーがログインしたら、古いハッシュを削除してください。
PostgreSQL の既存の bcrypt ハッシュを移行できますか?
直接はできません。crypt() は PBKDF2 形式ではないソルトやハッシュに対して NULL を返すため、pgcrypto の bcrypt ハッシュはここでは検証できません。既存の列にそのまま保持し、上の SHA2 ハッシュと同じ方法で、各ユーザーの次回のログイン成功時に再ハッシュしてください。PostgreSQL から MySQL への移行ガイドに拡張機能の完全な対応表があります。
保存されたハッシュにはソルトが含まれていますか?
はい。crypt() の出力は、アルゴリズム、反復回数、ソルト、ハッシュを 1 つの文字列にエンコードしています。ソルトを別途管理する必要はありません。
トラブルシューティング
関連項目
- MySQL でのデータのハッシュ — 整合性チェックや重複排除のための、パスワード以外のハッシュ
- MySQL での対称暗号化 — (ハッシュではなく) 暗号化が正しい選択となるとき
- MySQL でのランダムデータの生成 — 暗号学的に安全なソルトとトークンの生成