レッスン 2-3
クロスサイトリクエストフォージェリ
ログイン済みの
ブラウザは
なぜ通るのか
会員が
ここで、
クロスサイト
本人の要求と送らされた要求が混ざる所
サーバーから
悪意が
3 つの守り
守りは、
| 守り | 何を見るか |
|---|---|
| トークン | 自分の |
| Origin の確かめ | ブラウザが |
| SameSite | クッキーを |
トークンと
XSS との違い
前の
| XSS | CSRF | |
|---|---|---|
| 何が | 攻め手の | ブラウザが |
| 攻め手に | ページの | 応答は |
| 止める所 | 出力の | 要求が |
CSRF で
脆いコードと直したコード
ラボの127.0.0.1:8000 の
GET で受けるか、POST だけを受けるか
def change_email(req):sid = req.cookies.get("sid")user = SESSIONS.get(sid)if user is None:return 401user["email"] = req.params["email"]return 200def change_email(req):sid = req.cookies.get("sid")user = SESSIONS.get(sid)if user is None:return 401if req.method != "POST":return 405user["email"] = req.params["email"]return 200脆い方は、
ただし、
クッキーだけで本人とみなすか、出どころも見るか
def change_email(req):sid = req.cookies.get("sid")user = SESSIONS.get(sid)if user is None:return 401if req.method != "POST":return 405user["email"] = req.params["email"]return 200SITE = "http://127.0.0.1:8000" def change_email(req):sid = req.cookies.get("sid")user = SESSIONS.get(sid)if user is None:return 401if req.method != "POST":return 405if req.headers.get("Origin") != SITE:return 403sent = req.params.get("csrf", "")tok = user["csrf"]if not hmac.compare_digest(sent, tok):return 403user["email"] = req.params["email"]return 200直した方は
Origin がcompare_digest を
クッキーに印を付ける
def session_cookie(sid):return "sid=" + sid + "; Path=/"def session_cookie(sid):return ("sid=" + sid + "; Path=/""; Secure; HttpOnly""; SameSite=Lax")SameSite は、
OWASP は、
ログでの見え方と検知
CSRF の
change_email 403 reason=originorigin=http://127.0.0.1:9000user=1042この
| 見る物 | な |
|---|---|
| Origin と | ふだんの |
| 断った | どの |
| GET で | コードの |
あわせて、
直し方と、直ったことの確かめ方
自分の
- 作業用の
フォルダに、 セッションを 1 つ 持つ 表と、 上の 関数を 置く。 ログインした 利用者の メールアドレスを 1 つ 入れておく - 脆い
関数に、 同じ クッキーを 付けた GET の 要求を 渡し、 メールアドレスが 変わる ことを 確かめる - 別の
出どころ (Origin が 127.0.0.1:9000) から、トークンの 無い POST を 渡し、 これも 変わる ことを 確かめる - 関数を
直した コードに 置き換え、 2 と 3 が 405 と 403 で 止まり、 自分の ページからの POST だけが 通る ことを 確かめる - 下の
試験を 足し、 直す前の コードに 戻すと 試験が 落ちる ことも 確かめる - 終わったら、
作業用の フォルダごと消す
OTHER = "http://127.0.0.1:9000" def test_get_does_not_change(sid):req = Req("GET", {"email": "b@x.test"},{"sid": sid}, {"Origin": SITE})assert change_email(req) == 405 def test_other_origin_refused(sid):req = Req("POST", {"email": "b@x.test"},{"sid": sid}, {"Origin": OTHER})assert change_email(req) == 403試験は
フレームワークに
関わる事例
IPA の
根本的な
確認クイズ
1 問目
セッションの
- ア Lax なので、
別の サイトからの 変更は止まる - イ 別の
サイトからの リンクで 移動すると、 クッキーが 付き、 変更が通る - ウ GET には
クッキーが 付かないので、 ログインしていても 変更できない
答えと理由を見る
答え イ
Lax は、
2 問目
トークンも
- ア トークンが
あるので、 XSS が あっても CSRF は防げる - イ ページの
中で 動く スクリプトは トークンを 読めるので、 CSRF の 守りも 越えられる - ウ XSS と
CSRF は 関係が無い
答えと理由を見る
答え イ
XSS の
説明課題
次の
- XSS と
CSRF の 被害の 出方の違い
模範解答を見る
XSS では、
一次資料
どれも
- Cross-Site Request Forgery Prevention Cheat Sheet (OWASP、英語)。
同期トークンの 型、 Origin ヘッダーの 確かめと 付かない 場合、 SameSite の 3 つの 値と Lax の 限界、 XSS が あれば 対策を 越えられること - 安全な
ウェブサイトの 。作り方 1.6 CSRF クロスサイト・ リクエスト・ フォージェリ (IPA、 日本語) 根本的解決の 3 つの 型 (POST で 受けて 秘密の 値を 確かめる型、 パスワードを 入れ直す型、 Referer を 確かめる 型) と Referer の 型の 注意、 組み込み製品の 管理画面の 届出の例 - Cookies HTTP State Management Mechanism (IETF、
英語、草案) 。RFC 6265bis の 草案。 SameSite の Strict、 Lax、 None の定め - Cross Site Scripting Prevention Cheat Sheet (OWASP、英語)。
XSS との 被害の 出方の 違いを 比べる ための、 XSS の 側の資料
次へ
次の