説明
HttpOnlyがないCookieは、document.cookie などのクライアント側JavaScriptから読み取れます。XSSが発生すると、攻撃者が認証Cookieやセッショントークンを盗み、ユーザーになりすます可能性があります。HttpOnlyはページのスクリプトによるCookie値の読み取りを制限しますが、XSS自体やブラウザー全体の侵害を防ぐものではありません。
想定される影響
- セッションの乗っ取りと他人の権限でのアプリケーションへのアクセス
- 長期間有効なセッションや弱い再認証と組み合わさったアカウントの乗っ取り
- 盗まれた認証済みセッションを使った機密情報へのアクセス
対処方法
- サーバー発行の機密CookieにはHttpOnlyを設定してください。ExpressやNext.jsでは
httpOnly: trueを指定し、Node.jsのSet-CookieヘッダーにはHttpOnlyを含めてください。 - HTTPSでのみ送信する
Secure、SameSite(StrictまたはLax)、適切なPath/Domain、有効期限(Max-Age/Expires)も設定してください。 - 機密性のあるセッションIDやアクセストークンには、ローカルストレージよりHttpOnly Cookieを優先してください。必要に応じてサーバー側のセッションストアやローテーションを使ってください。
- フレームワークごとの例:
- Express:
res.cookie(name, value, { httpOnly: true, secure: true, sameSite: 'Strict' }) - Koa: HttpOnlyは既定でtrueです。
httpOnly: falseで無効にしないでください。 - Next.jsのServer Function/Route Handler:
(await cookies()).set(name, value, { httpOnly: true, secure: true, sameSite: 'strict' }) - Node http:
Set-Cookieヘッダーに; HttpOnlyを含めてください。
- Express:
- 入力検証、出力エンコード、CSPでXSSのリスクを減らしてください。
例
変更前
javascript
// 変更前: HttpOnlyがありません。
const crypto = require("crypto");
const express = require("express");
const app = express();
app.get("/signin", (req, res) => {
const token = crypto.randomBytes(32).toString("base64url");
// HttpOnlyがないためdocument.cookieから読み取れます。
res.cookie("auth", token, {
secure: true,
sameSite: "Lax",
path: "/",
});
res.send("signed in");
});
app.listen(3000);
変更後
javascript
// 変更後: HttpOnlyを設定します。
const crypto = require("crypto");
const express = require("express");
const app = express();
app.get("/signin", (req, res) => {
const token = crypto.randomBytes(32).toString("base64url");
// HttpOnly、Secure、SameSiteを設定します。
res.cookie("auth", token, {
httpOnly: true,
secure: true,
sameSite: "Strict",
path: "/",
maxAge: 10 * 60 * 1000, // 10分
});
res.send("signed in");
});
app.listen(3000);
説明:
- 変更前: ブラウザーのJavaScriptが
document.cookieで値を読み取れます。XSSによってCookieが漏えいすると、セッションを乗っ取られるおそれがあります。 - 変更後: HttpOnlyがCookie値へのスクリプトからのアクセスを防ぎます。SecureとSameSiteで通信とCSRFへの保護も加えます。XSS自体への対策は別途必要です。