会員 12 万人分のデータが流出
ある通販サイトから、会員 12 万人分のメールアドレスとパスワードが流出しました。
同じパスワードを、銀行やほかのサイトでも使っている人は少なくありません。パスワードがそのまま読めれば、攻撃者はほかのサイトにも入れてしまいます。
きちんと作られたシステムは、パスワードそのものを保存しません。では、何を保存するのでしょうか。
このレッスンのゴール
メモ
パスワードをハッシュで保存する理由を説明できる。
キーワード
| ことば | いみ | れい |
|---|---|---|
| 平文 | だれでもそのまま読める文字です。 | |
| ハッシュ関数 | 文字列から決まった長さの値を作る計算です。 | SHA-256 |
| ハッシュ値 | ハッシュ関数から出てくる値です。元には戻せません。 | |
| ソルト | ハッシュにする前に足すランダムな文字列です。 | |
| 情報漏えい | 情報が、見るべきでない人の手に渡ることです。 |
学生が入力するセルは、このプレビューでは空白です。
ハッシュは一方通行の計算
ハッシュ関数は、どんな文字列からも決まった長さの値を作ります。この値がハッシュ値です。
同じ文字列からは、いつも同じハッシュ値ができます。1 文字でも違えば、まったく別の値になります。
そして、ハッシュ値から元の文字列に戻す方法はありません。だから保存しても読まれません。
試す: パスワードをハッシュにする
import hashlib
def to_hash(text):
# hashlib は文字ではなくバイト列を受け取るので encode() します
return hashlib.sha256(text.encode()).hexdigest()
print(to_hash("Umeda2026"))
print(to_hash("Umeda2026"))
print(to_hash("umeda2026"))
print("長さ:", len(to_hash("a")), len(to_hash("とても長いパスワードの例です")))
# "Umeda2026" の 1 文字を変えて、もう一度実行してください。
ログインはハッシュ値どうしを比べる
登録のとき、システムはパスワードのハッシュ値を作り、それだけを保存します。
ログインのときは、入力された文字列のハッシュ値を作ります。保存してある値と同じなら、本人と判断します。
システムはパスワードを知る必要がありません。データベースを盗まれても、出てくるのはハッシュ値だけです。
よくある思い違い
注意
ハッシュと暗号化は同じだと考える方がいます。暗号化したデータは、鍵があれば元に戻せます。ハッシュ値は、鍵があっても戻せません。パスワードはだれにも読めなくてよいので、ハッシュで保存します。
ソルトで同じパスワードを見分けにくくする
二人が同じパスワードを使うと、ハッシュ値も同じになります。攻撃者には、それがすぐ分かります。
よく使われるパスワードのハッシュ値を集めた一覧と照らし合わせる攻撃もあります。
そこで、一人ずつ違うソルトを足してからハッシュにします。ソルトはハッシュ値と一緒に保存します。秘密にする必要はありません。
試す: ソルトを足す
import hashlib
def to_hash(text):
return hashlib.sha256(text.encode()).hexdigest()
# 二人の職員が、たまたま同じパスワードを選びました
print("田中:", to_hash("Umeda2026")[:16])
print("佐藤:", to_hash("Umeda2026")[:16])
# 一人ずつ別のソルトを足してからハッシュにします
print("田中:", to_hash("x7Kp" + "Umeda2026")[:16])
print("佐藤:", to_hash("m2Rw" + "Umeda2026")[:16])
# 佐藤さんのソルトを "x7Kp" に変えると、どうなるか試してください。
実際の職場では
ヒント
SHA-256 は計算が速いので、総当たりで試す攻撃者にも有利です。実際のシステムでは bcrypt や Argon2 のような、わざと遅いハッシュを使います。ソルトも自動で付きます。考え方はこのレッスンと同じです。