パスワードの保存 — 漏れたあとに、何日持ちこたえられるか
「パスワードはハッシュ化していたので安全」と発表した数日後、大半が元に戻され、他のサービスで不正ログインが続いた。速いハッシュは、漏れた瞬間から総当たりの的になる。
この記事の進み方
What — 漏れたハッシュは、どう元に戻されるか
パスワードを保存するときにハッシュ化するのは、DB が漏れてもパスワードそのものを渡さないためです。ハッシュ関数は一方向で、値から入力を計算できません。
ところが、計算できないことと、見つけられないことは別です。
- 1テーブルを手に入れるハッシュ値とメールアドレス軽い
- 2同じハッシュ値をまとめる同じパスワードは同じ値になる重い
- 3よく使われるパスワードを試す過去の流出から集めた一覧重い
- 4規則的に変形して試す末尾に数字、記号に置き換え重い
- 5他のサービスで試す使い回しを狙う重い
どの段も、ハッシュの計算が速いほど早く進む。遅くする仕組みが、そのまま時間稼ぎになる。
攻撃者は逆算しない。候補をハッシュ化して、一致するものを探す。速いハッシュほど、1秒に試せる候補が多い。
- ハッシュ関数
- 入力から固定長の値を計算する関数。同じ入力は同じ値になり、値から入力は計算できない。
- ソルト
- 利用者ごとに異なるランダムな値。パスワードに足してからハッシュ化し、同じパスワードでも違う値にする。
- ストレッチング
- ハッシュの計算を意図的に重くすること。1回の照合に時間やメモリを要するようにする。
- ペッパー
- DB とは別の場所に置く秘密の値。DB だけが漏れても、それが無ければ照合できない。
速さは、利用者ではなく攻撃者の味方
SHA-256 のような汎用のハッシュ関数は、速く計算できるように作られています。ファイルの改ざん検知や署名では、それが長所です。
パスワードの保存では、この速さが逆に働きます。
- 利用者がログインするとき: 1回計算するだけ。1回が1ミリ秒でも1秒でも、体感はあまり変わらない
- 攻撃者が総当たりするとき: 数十億回、数兆回と計算する。1回あたりの時間が、そのまま所要時間に掛かる
1回あたりの計算を重くすると、利用者の負担はほとんど変わらず、攻撃者の負担だけが桁違いに増えます。 パスワード用のハッシュ関数(Argon2id、scrypt、bcrypt)は、この重さを意図して設計され、重さを調整できるようになっています。
パスワードに利用者ごとのランダムなソルトを足してから SHA-256 でハッシュ化し、ソルトは同じ行に保存しています。テーブルが流出したとき、特定の1人のパスワードを総当たりで見つける時間は、ソルトが無い場合と比べてどうなりますか?
Why — なぜ「ハッシュ化」だけでは足りないのか
パスワードの保存で守りたいのは、流出を防ぐことだけではありません。流出は、脆弱性、内部不正、バックアップの紛失など、いくつもの経路で起きえます。
だから本当に問うべきは、**「漏れたあと、どれだけ時間を稼げるか」**です。
稼いだ時間で、サービス側は流出に気づき、全員にパスワードの変更を求め、使い回しの危険を知らせられます。数日で大半が割れるなら、知らせる前に被害が広がります。 数年かかるなら、ほとんどの会員は間に合います。
漏れた瞬間に全部読める
password = 'hunter2'- 漏れたあと
- **即座に全員分**
- 同じパスワードの人
- そのまま見える
- 管理者から
- **読める**
- 稼げる時間
- 0
- –DB を見られる人全員が、会員のパスワードを知っている状態
- –「パスワードを忘れた」ときに元のパスワードを送れるサービスは、これか暗号化
- –論外だが、ログや問い合わせの記録に平文が残っている、という形で起きがち
下に行くほど、漏れたあとに稼げる時間が長い。「元に戻せないか」ではなく「見つけるのにどれだけかかるか」で比べる。
自分で組み合わせない
パスワード用のハッシュは、実績のあるライブラリの関数を、その推奨設定で使うのが基本です。
- ソルトの生成、ハッシュ値の文字列への埋め込み、照合時の比較は、ライブラリが面倒を見る
- 比較を
==で自前に書くと、一致した文字数によって処理時間が変わり、手がかりを与えることがある - bcrypt は入力の先頭72バイトまでしか使わないなど、関数ごとの制約がある。長い入力を前処理する場合は、その方法もライブラリの推奨に従う
重さの設定は、ログイン1回あたりに許容できる時間(数十〜数百ミリ秒)を目安にし、計算機が速くなるのに合わせて定期的に引き上げます。設定はハッシュ値の文字列に含まれるので、次のログインのときに新しい設定で作り直すことができます。
パスワードを AES で暗号化して DB に保存しています。鍵はアプリの設定ファイルにあります。DB と一緒に、アプリのサーバーの設定ファイルも流出しました。どうなりますか?
演習 — まず自分で判断する
解説を読む前に、まず自分で判断してみてください。ここで一度詰まっておくと、 次の節の判断軸が「なるほど」ではなく「そう来たか」に変わります。
新しく作るサービスで、パスワードをどう保存しますか?
- メールアドレスとパスワードでログインする
- ログインのピークは毎秒50回程度。サーバーは数台
- 数年運用する予定で、途中で設定を強くしたくなる可能性がある
- チームにセキュリティの専門家はいない
- 秘密情報はシークレット管理サービスに置ける
- · 流出したあと、1人あたり何回の照合を強いられるか
- · 何年か後に設定を強くしたいとき、既存の会員をどう移すか
- · 重い照合が、サーバーの負荷と攻撃の入口にならないか
流出の発表文の案に「パスワードはハッシュ化しているため安全です」と書かれています。広報とマネジメントに、この表現の何が問題かと、何を書くべきかを伝えてください
- パスワードは SHA-256 で、ソルト無しでハッシュ化されていた
- 相手は技術的な詳細より、会員への影響と会社の信頼を気にしている
- 発表は今日中に出す必要がある
読み終わりましたか?
読了にすると、これを前提とする記事がロードマップで開放されます。