クリーム色の背景、色付き表示、高コントラスト、大きな文字のほうが読みやすいですか?配色と文字を選ぶと、すべてのページに一度で反映されます。

無料レッスン

パスワードの保存とセッション管理

このレッスンのあとで: パスワードをソルト付きのハッシュで保存し、セッションの札と期限を安全に扱うコードを書ける。

60分のレッスンコマンド3件SQL インジェクションのラボ:弱い検索を攻撃し、クエリを直して確かめる

パスワードの安全な保存とは

パスワードの安全な保存とは、パスワードそのものではなく、元に戻せない形の値だけを保存することです。セッション管理は、ログイン後の利用者を推測できない札で見分け、期限が来たら無効にする仕組みです。

大学の学生ポータルのデータベースが漏れたとします。パスワードがそのまま入っていれば、全員が他のサイトでも危なくなります。

このレッスンのゴール

メモ

パスワードをソルト付きのハッシュで保存し、セッションの札と期限を安全に扱うコードを書ける。

今日のキーワード

ことばいみ
ハッシュ値文字から作る、元に戻せない決まった長さの値です。
ソルト利用者ごとに違う、ランダムな足し文字です。
セッションログインしてから、ログアウトまでのひとまとまりです。
トークンログイン済みの利用者を見分ける、推測できない札です。
有効期限その札を使ってよい、最後の時刻です。
Cookieブラウザが覚えて、毎回サーバーに送る小さな文字です。

学生が入力するセルは、このプレビューでは空白です。

たった1つのルール

注意

試してよいのは、自分専用のラボのコピーだけです。このラボは、わざと弱く作った店で、インターネットにはつながっていません。許可のない他人のシステムに同じことをするのは、不正アクセス禁止法に触れる犯罪です。

パスワードはハッシュにして保存する

ハッシュ関数は、文字から決まった長さの値を作ります。同じ文字からは、いつも同じ値ができます。値から元の文字には戻せません。

ログインのときは、入力を同じ関数にかけ、保存した値と比べます。パスワードそのものは、どこにも残りません。

abc のハッシュ値

コマンド
printf 'abc' | sha256sum

ここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。

password のハッシュ値

コマンド
printf 'password' | sha256sum

ここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。

2つの答えを読む

どちらも、64文字の16進数を表示します。3文字の abc も、8文字の password も、同じ長さです。何度実行しても、同じ文字からは同じ値になります。

password の値は、世の中の誰もが知っています。攻撃する人は、よく使われる文字の値を、一覧にして持っているからです。

ソルトで同じ値をなくす

ハッシュだけでは、同じパスワードの人は同じ値になります。そこで ソルト(salt)を使います。利用者ごとに違うランダムな文字を足してから、ハッシュにします。

ソルトは隠さず、ハッシュ値の横に保存します。目的は隠すことではなく、一覧を使えなくすることです。

ソルトで値が変わる

コード: python
import hashlib

def hash_password(password, salt):
    # 遅いハッシュを使います。回数を増やすほど、試す側も遅くなります。
    return hashlib.pbkdf2_hmac("sha256", password.encode(), salt.encode(), 100000).hex()

# salt を変えて、実行します。
a = hash_password("sunflower", "salt-A")
b = hash_password("sunflower", "salt-B")
print(a == b)
print(a == hash_password("sunflower", "salt-A"))
print(len(a))

保存の仕方を比べる

保存の仕方漏れたときに起きること
そのまま保存すぐに読まれる。他のサイトの口座も危ない
速いハッシュを1回だけ1秒に何億回も試され、弱い語はすぐ破られる
ソルトなしのハッシュ同じパスワードの人が、一度にわかる
ソルト付きの遅いハッシュ1人ずつ、時間をかけないと試せない

学生が入力するセルは、このプレビューでは空白です。

よくある間違い

注意

「SHA-256 で1回ハッシュにすれば十分だ」と考える人がいます。それは違います。速い関数は、攻撃する側にも速いのです。パスワードには、ソルトを付けた、わざと遅いハッシュを使います。

セッションの札は推測できない乱数にする

ログインすると、サーバーは セッション(session)を作り、トークン(token)という札を渡します。ブラウザは Cookie で札を送り続けます。

札を推測できれば、他人になりすませます。だから、安全な乱数で、十分に長く作ります。Python では secrets を使い、random は使いません。

安全な乱数で札を作る

コード: python
import secrets

# 16バイトを16進数にすると、32文字になります。
token = secrets.token_hex(16)
print(len(token))
print(token == secrets.token_hex(16))

ラボの Python で札の長さを見る

コマンド
docker exec app python -c "import secrets; print(len(secrets.token_hex(16)))"

ここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。

セッションには期限と終わりが要る

セッションの期限は2種類あります。何もしないまま一定時間が過ぎると切れる アイドル期限 と、ログインから最大の長さを決める 絶対期限 です。

ログアウトは、ブラウザの Cookie を消すだけでは足りません。サーバーの側でも、その札を無効にします。

札を守る Cookie の3つの設定

設定守ること
HttpOnly画面の JavaScript から、札を読めなくする
Secure暗号化した通信でだけ、札を送る
SameSite他のサイトから起きた送信に、札を付けにくくする

学生が入力するセルは、このプレビューでは空白です。

このラボとソースについて: SQL インジェクションのラボ:弱い検索を攻撃し、クエリを直して確かめる

授業で使いますか?このモジュールを学生に割り当てると、教員用ガイド、自動採点つきの課題、学生ごとのラボを使えます。