3秒でわかる
ログイン中の利用者のセッション ID を盗み、その人になりすまして操作する攻撃。パスワードを知らなくても侵入できるため、Cookie の守り方が要点になります。
もう少し詳しく
どういうものか
セッションハイジャックは、ログイン済みの利用者を識別しているセッション ID を攻撃者が入手し、それを自分のリクエストに載せて本人として振る舞う攻撃である。
HTTP はリクエストごとに独立していて、前のリクエストとの関係を持たない。そのためログイン後は、サーバーが発行したセッション ID を Cookie に入れて毎回送り、それで本人を識別する。この ID が「入場券」そのものなので、盗まれた時点でパスワードを知らなくても中に入れてしまう。
なぜ必要か
対策を考える前に、盗まれる経路を押さえておく。主な経路は 3 つある。
1 つ目は盗聴で、暗号化されていない通信路を流れる Cookie を読み取る。公衆無線 LAN で起きやすい。2 つ目はクロスサイトスクリプティング (XSS) で、注入した JavaScript から document.cookie を読んで外部へ送る。3 つ目はセッション ID の推測で、連番や時刻を元にした ID を生成していると、他人の値を計算で当てられる。
具体例
Cookie の属性で、上の経路のうち 2 つを塞げる。
res.cookie("sid", sessionId, {
httpOnly: true, // JavaScript から読めなくする (XSS 経由の窃取を防ぐ)
secure: true, // HTTPS の通信でしか送らない (盗聴を防ぐ)
sameSite: "lax", // 別サイトからの送信を制限する
maxAge: 1000 * 60 * 60 * 2,
});セッション ID そのものは、推測できない長さと乱数で作る。
import crypto from "node:crypto";
const sessionId = crypto.randomBytes(32).toString("base64url");そしてログインに成功した時点で、それまでのセッション ID を捨てて新しく発行し直す。
req.session.regenerate((err) => {
if (err) return next(err);
req.session.userId = user.id;
});つまずきやすいところ
ログイン後に ID を作り直す処理を省くと、セッション固定攻撃が通る。攻撃者が用意した ID を先に利用者へ掴ませ、その利用者がログインすると、攻撃者が持っている同じ ID が認証済みに変わってしまう。
httpOnly を付けたから XSS は怖くない、と考えるのも危うい。Cookie を読めなくても、注入されたスクリプトは利用者の権限のままリクエストを送れるので、被害の形が変わるだけである。XSS そのものは出力のエスケープで塞ぐ。
セッションの有効期限を無期限にしている実装も残る。盗まれた券がいつまでも使えることになるため、期限とログアウト時のサーバー側破棄を必ず入れる。
似た用語との違い
| 攻撃 | 攻撃者がすること |
|---|---|
| セッションハイジャック | 有効なセッション ID を盗んで使う |
| セッション固定 | 自分が用意した ID を利用者に使わせる |
| CSRF | ID を盗まず、ログイン中の利用者に意図しない操作を送らせる |
| XSS | ページに script を注入する。ID の窃取手段にもなる |