はじめに
サイト間シングルサインオン(SSO)の心臓部が、この「ハンドオフトークン」です。あるサイトでログイン済みのユーザーが別サイトへ移る一瞬に、「この人はもうログイン済みですよ」という証明書を安全に手渡すための仕組みですね。
ただ、証明書を渡すと言葉にすると簡単ですが、Webの世界ではその紙切れが盗まれたり偽造されたりする前提で設計しなければなりません。この記事では、ハンドオフトークンに何を入れ、どう署名し、どうやって「一瞬しか使えない使い捨て」にしているのかを解説します。
トークンに何を入れるか
中身は「誰が・どこへ・いつまで」
ハンドオフトークンは、それ自体が短い情報のかたまりです。最低限、次のような要素を持たせます。
大切なのは、トークンにパスワードのような秘密情報を入れないことです。あくまで「このユーザーのログインを引き継いでよい」という一時的な許可証にとどめ、万一漏れても被害が限定されるようにします。
なぜ最小限にとどめるのか
トークンはURLに載って別サイトへ飛んでいきます。つまりブラウザの履歴やサーバーのアクセスログに残る可能性がある、ということです。
だからこそ、そこに載せる情報は「漏れても許容できるもの」だけにします。ユーザー識別子も、内部IDそのものではなく、引き継ぎに使うためだけの参照値にしておくと安心です。中身を最小にすることは、それ自体が立派なセキュリティ対策なんです。
HMAC署名で改ざんを防ぐ
共有シークレットによる署名
トークンが途中で書き換えられていないことを保証するために、HMAC署名を使います。これは、全サイトで共有している秘密の鍵(シークレット)を使って、トークンの中身から一意の署名文字列を計算する方式です。
サイトAが共有シークレットでトークン本体の署名を計算し、末尾に付ける
サイトBが受け取ったトークン本体から、同じシークレットで署名を計算し直す
自分で計算した署名と、トークンに付いていた署名が一致すれば改ざんなし
シークレットを知らない第三者は、中身を書き換えても正しい署名を作れません。だから「ユーザーIDだけこっそり別人に差し替える」といった細工が成立しないわけです。
なぜHMACなのか
署名と暗号化は別物
HMAC署名はトークンを暗号化するものではありません。中身は読める状態のまま、「改ざんされていないこと」だけを保証します。中身を秘密にしたいのではなく、偽造を防ぎたいのが目的なので、これで十分なんです。
公開鍵暗号のような重い仕組みを使わず、共有シークレットによるHMACを選んだのは、すべてのサイトが同じ運営主体の管理下にあり、シークレットを安全に共有できる前提があったからです。シンプルな仕組みほど、運用でのミスも減らせます。
短命・使い捨てで再利用を防ぐ
短い有効期限(TTL)
署名で偽造を防げても、正規のトークンそのものが盗まれる可能性は残ります。そこで効いてくるのが短い有効期限です。
ハンドオフトークンは、サイトを移動する数秒〜十数秒のためだけに存在します。だから有効期限も極端に短く設定します。仮に盗まれても、攻撃者が使おうとした頃にはとっくに期限切れ、という状態を作るわけです。長生きするトークンは、それだけで攻撃対象になります。
ワンタイム(使い捨て)
盗んだトークンを期限内なら何度でも使える。リプレイ攻撃が成立してしまう
1度検証に使われたトークンは無効化。同じトークンの2回目は必ず失敗する
有効期限の短さに加えて、「1度使ったら二度と使えない」という制約を重ねます。受入側は検証に成功したトークンのワンタイムIDを記録し、同じIDが再び来たら拒否します。これでリプレイ攻撃(盗んだトークンの使い回し)を封じられます。
多層防御という考え方
署名・TTL・ワンタイムは、それぞれ別々の攻撃を防いでいます。署名は改ざんを、TTLは時間差の悪用を、ワンタイムは使い回しを防ぐ。1つが破られても他が残る、という多層防御の発想です。
セキュリティは「1つの完璧な対策」より「複数のそこそこの対策の重ね合わせ」のほうが強いことが多いんです。ハンドオフトークンは、その好例と言えます。
まとめ
ハンドオフトークンは、サイトをまたぐ一瞬だけ有効な「使い捨ての許可証」です。設計の要点は次のとおりでした。
- 中身は最小限:秘密情報は入れず、引き継ぎに必要な情報だけを載せる
- HMAC署名:共有シークレットで改ざんを検知する
- 短いTTL:盗まれても間に合わないほど短命にする
- ワンタイム:1度使ったら無効化し、再利用を防ぐ
このトークンを受け取った側が、実際にどう検証してセッションを確立するのかは「SSOコールバックとセッション確立のフロー」で解説します。SSO全体の位置づけは「複数ECサイト間のシングルサインオン設計」をご覧ください。