セッションハイジャックとは、コンピュータネットワーク通信におけるセッション(特定利用者間で行われる一連の通信群)を、通信当事者以外が乗っ取る攻撃手法である。HTTPにおけるWebセッションのハイジャックを指すことが多いが、この用語が示す範囲は必ずしもこれに限定されるわけではない。

## 概要

ネットワーク通信では当事者間で複数回の通信をやりとりしながら一連の処理を行う事があり、このような一連の処理をセッションと呼ぶ。たとえばユーザがWebアプリケーションを使うとき、ユーザがそのアプリケーションにログインし、アプリケーションと「双方向」通信を行い、最後にログアウトするまでを1つのセッションとみなす事ができる。またストリーミングによる動画配信では、動画配信が始まってから完了するまで「連続」してデータを送り、これも1つのセッションとみなせる。このような「双方向」や「連続」を伴う一連のやり取りが一つの「セッション」として管理される。

各セッションは、セッションごとに割り振られるセッションIDを用いて識別され、通信の当事者同士は通信の際にセッションIDを送りあうことでどのセッションに関する通信であるのかを明示する。

セッションハイジャックは通信の当事者でない第三者(攻撃者)が何らかの手段でセッションIDを知ることにより、セッションを乗っ取る攻撃手法を指す。これを悪用すると、例えばユーザが銀行のシステムにログインして利用しているセッションを乗っ取り、ユーザの口座から攻撃者の口座に不正に振り込みを行う、といった事ができてしまう可能性がある。

というのも、銀行システムを含めたWeb上のアプリケーションではユーザが最初にログインする際にはパスワードの入力を求めるなどしてユーザを認証するが、一度ユーザがログインに成功したら、以後の通信ではパスワードを求めずにセッションIDのみでユーザを識別する実装になっていることも多いからである。したがってユーザがログインした後に攻撃者がセッションIDの奪取に成功すれば、攻撃者がユーザのパスワードを知らなくともセッションを乗っ取って不正をはたらく事が可能である。

## HTTPセッション

HTTPはもともとブラウザの要求に対してWebページを返すような一往復の通信が想定されており、HTTPそれ自身はセッション管理の仕組みを備えていないため、Webアプリケーションの側でセッション管理の仕組みを用意し、ブラウザ側にセッションIDを持たせる必要がある。しかしこのセッション管理の仕組みが不適切であると、セッションをハイジャックされてしまう危険がある。

Webアプリケーションに対するセッションハイジャックは以下の三種類に分類できる:セッションIDの推測、セッションIDの盗み出し、セッションID固定化攻撃。第一の方法であるセッションIDの推測は、セッションIDを推測しやすい方法で割り振っている場合に可能な攻撃で、例えばセッションIDを連番、時刻、ユーザID、メールアドレスといったものにしていると、攻撃者にセッションIDを推測される危険がある。

第二の方法であるセッションIDの盗難は、Webアプリケーションの脆弱性(例えばクロスサイトスクリプティング、HTTPヘッダ・インジェクション、ミドルウェアの脆弱性)がある場合に可能な攻撃で、これらの脆弱性を利用してブラウザに保管されたセッションIDを盗む。またセッションIDをURLに埋め込んでいるケースではリファラを悪用した以下のような盗難方法が知られている:例えばSNSのユーザのセッションをハイジャックする場合、攻撃者は標的となるユーザに自身のサイトへのリンクをSNS経由で伝える。ユーザがSNS上のリンクをクリックして攻撃者のサイトにアクセスすると、攻撃者のサイトにはユーザが直前にいたサイト(すなわちSNS)のURLがリファラとして伝わるので、SNSのサイトでセッションIDをURLに埋め込んでいる場合には、攻撃者にセッションIDが知られてしまう。

### セッションID固定化攻撃

セッションハイジャックを行う第三の方法としてセッションID固定化攻撃(セッションフィクセーション攻撃、session fixation attack)が知られている。脆弱性をツリー型に分類するCWEではセッションID固定化攻撃を不適切な認証(CWE-287)による脆弱性のひとつとして分類している(CWE-384)。

前述のようにWebアプリケーションはユーザのブラウザにセッションIDを保持させる事でセッション管理を行っているが、この攻撃では何らかの不正な手段を用いて被害者のブラウザに攻撃者が用意したIDを入れ込む。これにより被害者とWebアプリケーションの間のセッションのIDは攻撃者が入れ込んだものになってしまう。攻撃者自身は当然このIDを知っているので、被害者のセッションのハイジャックが可能になる。

攻撃者がセッションIDをブラウザに入れ込む方法は様々だが、URLにセッションIDを埋め込んでいるタイプのWebアプリケーションの場合は、セッションID部分を攻撃者が指定したものに書き換えたURLを被害者にクリックさせる事でセッションID固定化が実現できる。一方、セッションIDをcookieに記憶させている場合は、cookieの書き換えが可能な脆弱性(クロスサイトスクリプティングやHTTPヘッダ・インジェクション)を利用してcookie内のセッションIDを攻撃者が指定したものに書き換える事ができる。

攻撃者が入れ込むセッションIDは、攻撃者自身がランダムに新しく生成するケースと、Webアプリケーションとの他のセッション(例えばWebアプリケーションと攻撃者とのセッション)のIDを流用するケースとがある。前者の場合、攻撃が成功するにはWebアプリケーションの側が攻撃者の生成したセッションIDを受け入れる必要がある。Webアプリケーションの側で自身の発行したセッションIDを全て管理していれば、Webアプリケーションは攻撃者の生成したセッションIDを受け入れずにすむはずだが、Webアプリケーションの開発言語の中には自身で発行してないセッションIDすらも受け入れてしまうものがあり(例えば古いバージョンのPHP)、これが原因で攻撃が可能になってしまう場合がある。このように任意のセッションIDを受け入れてしまうという言語特性をセッションアダプションという。

一方、別のセッションのIDを流用した攻撃の例としては、攻撃者はまずWebアプリケーションとセッションを貼り、そのセッションのIDを被害者のブラウザに入れ込むというものがある。この場合Webアプリケーションの側で自身の発行したセッションIDを管理していても、この攻撃を防げない。なぜなら被害者のブラウザに入れ込まれたIDは、Webアプリケーション自身が(攻撃者に対して)発行した正規のIDだからである。

### セッション管理方法と対策

WebアプリケーションとブラウザがセッションIDを送受信する方法として以下の3つが知られている:

1. cookie
2. フォームデータのhiddenフィールド
3. URL

第一の方法は RFC 6265 に規定されており、WebアプリケーションがSet-Cookieレスポンスヘッダを用いてcookieを発行し、ブラウザ側がそのcookieを自動的にサーバに送り返す。

第二の方法はセッションIDをフォームデータのhiddenフィールドとして渡す方法で、この方法を用いるにはページ遷移をフォームデータの送信の形で記述する必要がある。

第三の方法はURLにセッションIDを含める方法だが、すでに述べたようにセッションハイジャックの危険にさらされるので、特別な理由がない限り利用すべきではない。

したがって安全性を考慮した場合、第一もしくは第二の方法を用いてセッション管理を行うべきである。なお第二の方法のほうが第一の方法よりもセッションIDが攻撃者に漏れにくいが、第二の方法の場合、自然なハイパーリンクを実現するためにスクリプトを利用する必要があるため実装が複雑になる。

その他の対策方法として、ログインを伴うWebアプリケーションではログインの認証後にセッションIDを変更するというものがある。すでに述べたようにユーザがパスワードを求められるのはログインの認証時のみで以降はセッションIDを使ってユーザを識別する。したがってセッションIDがログイン前に攻撃者に漏れていてもログイン後のセッションをハイジャックされないようにするためにこの対策が有効になる。

またWebアプリケーションの開発ツール(Webアプリケーションフレームワーク)にはセッション管理機能を持ったものも多いので、セッション管理機能を自作せず、既存の開発ツールに付属したものを利用する方が良い。

## TCPコネクション

TCPはIP通信に対してコネクション機能を設けたものであり、最低限のセッション機能を設けたものともいえる。

TCPにおいてセッションIDに相当する管理項目は、IPアドレスとシーケンス番号である。送信元IPアドレスの詐称とTCPシーケンス番号予測攻撃を組み合わせることで、確立済みのTCPセッションに不正データを挿入することやセッションの強制切断を行うことが可能であり、セッションの乗っ取りが可能となる。

TCPシーケンス番号予測攻撃について、1985年にBob Morrisが攻撃手法をレポートしたこと、1995年にこの脆弱性を使った広範囲の攻撃が発生したこと(CA-1995-01)、2001年に不充分な実装に伴う問題が指摘されたこと(CA-2001-09)など、過去より何度か問題となっていたが、対策が行なわれている2008年現在では沈静化している。