セキュリティ●●●○○

SSO

Single Sign-On ・ えすえすおー

認証を IdP に集め、一度のログインを使い回して複数のサービスに入れるようにする仕組み。

✦ 30秒で試す — 航海パスワードを一度も渡していないサービスに、なぜか入れている停止の直後、この社員はメールを開けるか?予想してみる

概要

SSO(シングルサインオン)は、一度のログインで複数のサービスを使えるようにする仕組みです。朝一番に会社のアカウントでログインすれば、メール・チャット・勤怠・ファイル共有には、もうパスワードを入れずに入れます。企業で働く人が毎日体験しているこの動きが SSO です。中身は構造の転換で、各サービスが個別にパスワードを預かって認証する代わりに、認証を専門に担う一箇所(IdP、Identity Provider)に集め、各サービスはその結果を信頼します。

SSO は特定のプロトコルの名前ではなく、「一度のログインを使い回す」という設計と体験の名前です。実現の手段としては SAML や OIDC といった標準プロトコルが使われます。Google アカウントひとつで Gmail・YouTube・ドライブに入れるのはコンシューマ向けの SSO で、社給アカウントで数十の SaaS に入れるのはエンタープライズ SSO です。

「一度のログイン」の正体は、ブラウザに残る2種類のセッションです。IdP とのあいだの「SSO セッション」が生きているあいだは、別のサービスへ行っても IdP がログイン画面を出さずに認証結果を返します。そして各サービスは、受け取った結果をもとに自分のセッションを別に作ります。この二層を押さえると、SSO の便利さと落とし穴(IdP でログアウトしても各サービスには入れたまま、など)が同じ一つの仕組みから説明できます。

認証が一箇所に集まるので、本質は利便性よりもむしろセキュリティと管理にあります。MFA(多要素認証)の強制、アクセスポリシーの適用、退職者のアカウント停止を、その一箇所で全サービスにまとめて効かせられます。

なぜ生まれたか

サービスが増えるたびに、アカウントとパスワードも増えていきました。利用者は数十のパスワードを覚えきれず、使い回しや付箋のメモに頼ります。1つのサービスから漏れたパスワードで他のサービスにも入られ、使い回しは攻撃者にとって最も効率のよい侵入口になりました。管理者の負担も重く、入社のたびに数十のサービスでアカウントを作り、退職のたびにすべてを消して回ります。1つ消し忘れれば、退職者が社内データに入れる穴が残ります。「パスワードを忘れました」への対応がヘルプデスクの仕事の大きな割合を占める状況も、長く続きました。

この問題への最初の本格的な答えは、社内ネットワークの中から生まれました。1980年代に MIT の Project Athena で開発された Kerberos は、ログイン時に一度だけパスワードで認証して「チケット認可チケット(TGT)」を受け取り、以後はファイルサーバやプリンタなどサービスごとの入場券(サービスチケット)をそのチケットと交換で手に入れる、という方式を取りました。「一度の認証で得た証明を手元に持ち、サービスごとの入場券に換える」という SSO の原型です。Kerberos v5 は 1993年に RFC 1510 として標準化され、Windows 2000 の Active Directory が標準の認証方式に採用したことで、「Windows ドメインにログオンすれば社内のサーバに入れる」統合ログインが企業に広まりました。ただし Kerberos は、端末が認証サーバ(KDC)と直接通信できる同じ組織のネットワークを前提にしていて、インターネット越しの Web サービスや、会社をまたいだ連携には向きませんでした。

Web では別の壁がありました。Cookie は発行したドメインにしか送られないので、mail.example.com で作ったログイン状態を chat.example.net は読めません。そこで考え出されたのが、ブラウザを認証サーバへリダイレクトさせて往復させる方式です。2000年代初頭に Yale 大学で開発された CAS(Central Authentication Service)は、ブラウザを中央の認証サーバへ送り、認証サーバは自分のドメインにログイン状態の Cookie(Kerberos の TGT にあたるもの)を置き、サービスには使い捨てのチケットを URL に載せて持ち帰らせます。サービスはそのチケットを認証サーバに直接問い合わせて確かめます。「中央でのログイン状態は認証サーバのドメインの Cookie に置き、各サービスへはリダイレクトで結果を運ぶ」という、いまの Web SSO の基本の形がここでできあがりました。

残る課題は、別々の組織のあいだでも通じる共通の言葉でした。2002年に OASIS が SAML 1.0 を、2005年に SAML 2.0 を標準化し、署名付きの XML で「この IdP がこの人を認証した」と伝える形が企業間連携の標準になりました。2014年には OAuth 2.0 の上に認証を載せた OIDC が加わります。そしてクラウドの普及で1社が使う SaaS が数十〜数百になり、認証を IdP に集める SSO は「あれば便利」から「ないと管理できない」基盤になりました。

詳細

登場人物と信頼関係

SSO の登場人物は4つです。ログインする人、その人が操作するブラウザ、認証を担う IdP、そして実際に使いたいサービスである SP(Service Provider。OIDC では RP、Relying Party と呼びます)です。IdP と SP は直接には話さず、認証結果はブラウザのリダイレクトで運ばれます。ブラウザを独立した参加者として数えると、この先の流れもセッションの仕組みも見通しがよくなります。

前提として、IdP と各 SP のあいだには事前に信頼関係を結んでおきます。SAML ならメタデータを交換して IdP の署名検証用の証明書を SP に登録し、OIDC なら SP をクライアントとして登録します。SP は「この証明書で検証できる署名の付いた認証結果なら受け入れる」と設定されているので、パスワードを一切預からずに利用者を受け入れられます。署名の検証は公開鍵暗号の仕組みそのもので、IdP は秘密鍵で署名し、SP は公開鍵(証明書)で確かめます。この信頼は設定であって、通信の経路ではない点に注意してください。

SP-initiated フローを順に追う

最も一般的なのは、利用者が SP から使い始める「SP-initiated」フローです。認証が必要になった SP がブラウザを IdP へ送り出し、IdP が認証結果を持たせて送り返す、という往復が中心になります。

チャット SPIdPメール SPブラウザチャット SPIdPメール SPブラウザIdP は自分のドメインに SSO セッションの Cookie を置く2つ目のサービスではログイン画面が出ないメールを開く302 未ログインなので IdP へ認証リクエストを届けるログイン画面・MFAパスワードと MFA署名付きの認証結果を持たせて SP へ戻す認証結果を届ける署名を検証し、メール自身のセッション Cookie を発行チャットを開く302 IdP へ認証リクエスト・SSO セッションの Cookie 付きログイン画面を出さずに認証結果を返す認証結果を届けるチャット自身のセッション Cookie を発行

(1)利用者がメールを開くと、SP はログイン状態がないことを確かめ、ブラウザを IdP へリダイレクトさせます。URL には「どの SP からの依頼か」と、戻り先が含まれます。(2)IdP はログイン画面を出し、パスワードや MFA で本人を確かめます。パスワードを受け取るのは IdP だけで、SP は一度も見ません。(3)認証に成功すると、IdP は自分のドメイン(例: idp.example)にログイン状態を記録した Cookie を置きます。これが SSO セッションです。(4)IdP は署名付きの認証結果(SAML のアサーション、OIDC なら認可コードを経て受け取る ID トークン)を持たせて、ブラウザを SP へ戻します。(5)SP は署名・宛先・有効期限を検証し、利用者を確定させて、今度は自分のドメインに自分のセッション Cookieを発行します。

(6)続けてチャットを開くと、同じようにブラウザは IdP へリダイレクトされます。ただし今回は、ブラウザが idp.example 宛ての SSO セッションの Cookie を自動で添えるので、IdP はログイン画面を出さずに即座に認証結果を返します。利用者には「画面が一瞬切り替わっただけでログインできた」ように見えます。「一度のログインで複数のサービス」の正体は、この IdP への一瞬の往復です。

なお、IdP のポータル画面に並んだアプリのアイコンから始める形は「IdP-initiated」フローと呼ばれます。SP が依頼を出していないのに認証結果が届く形なので、依頼と応答を結びつけられず、認証結果の差し込みに弱くなります。SP 側で受け入れるかどうかは慎重に決めます。

セッションの二層構造

SSO を理解する鍵は、セッションが二層になっていることです。第1層は IdP とブラウザのあいだの SSO セッション、第2層は各 SP とブラウザのあいだのアプリセッションです。どちらも Cookie で保たれますが、発行するドメインも寿命を決める人も別々です。

ブラウザCookie はドメインごとに別々に保存バーは寿命の長さ(同じ縮尺)IdPidp.example第1層: SSO セッションidp.example の Cookie。寿命は IdP が決める8時間事前の信頼第2層: アプリセッション(SP ごと)メールmail.example の Cookie12時間チャットchat.example の Cookie24時間勤怠kintai.example の Cookie2時間IdP でログアウト・アカウント停止 → 消えるのは第1層だけ第2層は各 SP の寿命が尽きるまで(またはログアウトの通知が届くまで)生き残る
セッションの二層構造。第1層(SSO セッション)は IdP が、第2層(アプリセッション)は各 SP がそれぞれ別の寿命で管理する

SP は認証結果を受け取ったあとは自分のセッションだけで動き、リクエストのたびに IdP へ問い合わせることはしません。だから SSO は速く、IdP が少し止まっても使用中のサービスは動き続けます。その裏返しとして、次のことが起きます。

  • IdP でログアウトしても、SP には入れたまま。第1層を消しても、第2層のアプリセッションはその SP の寿命が尽きるまで生きています。
  • SP でログアウトしても、すぐまた入れてしまう。第2層だけを消しても、第1層が生きていれば、次にその SP を開いたとき IdP を一瞬くぐって黙ってログインし直します。共用端末で「ログアウトしたのに戻ってしまう」と言われるのはこれです。
  • 退職者のアカウントを IdP で止めても、即座には締め出せない。止まるのは新しいログインだけで、すでに発行された各 SP のセッションは残ります。チャットのように寿命を長くしている SP ほど、穴が長く開いたままになります。

下の部品では、SP のタブを順に開いてみてください。最初の1つだけ IdP のログイン画面を通り、2つ目からは IdP を一瞬くぐって戻ってくるはずです。そのあと IdP でログアウトしたり、アカウントを停止したりして、各セッションの寿命のバーがどうなるかを確かめてください。

⚡ 体験: SSO のセッションを二層で確かめる
サーバの世界 — IdP と SP はふだん直接は話さないブラウザの世界破線=リダイレクト認証結果はブラウザが運ぶ直通の経路なし(信頼は事前の設定だけ)IdPSSO セッションなしメールセッションなしチャットセッションなし勤怠セッションなしブラウザCookie はドメイン別メールチャット勤怠ブラウザの Cookie — ドメインごとに別の引き出し(バーの長さ=寿命、同じ縮尺)経過 0秒第1層第2層idp.example | SSO セッション(まだない)mail.example | メールのアプリセッション(まだない)chat.example | チャットのアプリセッション(まだない)kintai.example | 勤怠のアプリセッション(まだない)
時計
IdP → SP の通知
見つけたこと 0/4 — 次は「最初だけログイン」
あなたの操作から描かれるシーケンス図(直近12行)
ブラウザIdPメールチャット勤怠まだ何も起きていません

下のブラウザのタブ「メール」を押して開いてください。まだどこにもログインしていません。

ログアウトはなぜ難しいか

全サービスから一斉にログアウトさせる「シングルログアウト」は各プロトコルに仕様がありますが、実装は難しいことで知られています。問題は、IdP から各 SP のアプリセッションへどうやって「消して」と伝えるかです。

1つ目の方法は、ブラウザを経由して伝えるフロントチャネル・ログアウトです。SAML のシングルログアウトは、IdP がブラウザを各 SP のログアウト用 URL へ順にリダイレクトさせ、SP は自分の Cookie を消して IdP へ戻します。途中の1つの SP がエラーを返したり、利用者がタブを閉じたりすると、その先の SP には届きません。OIDC の Front-Channel Logout は、IdP のログアウト画面に各 SP のページを見えない iframe で埋め込んで一斉に呼び出す方式ですが、iframe の中の SP は「よそのサイトに埋め込まれた状態」なので、SP の Cookie は「サードパーティ Cookie」として扱われます。Safari や Firefox は既定でこれを遮断・分離するので、SP は自分のセッションを見つけられず、ログアウトが空振りします。

2つ目の方法は、ブラウザを通さずにサーバ同士で伝えるバックチャネル・ログアウトです。OIDC の Back-Channel Logout では、IdP が各 SP のサーバへ、署名付きの「ログアウトトークン」(JWT)を直接 POST します。ブラウザの状態に左右されないので確実ですが、SP 側にも条件があります。トークンに入ったセッション ID から自分のアプリセッションを探して消せるように、セッションをサーバ側に保存している必要があり、IdP から到達できるエンドポイントも公開しなければなりません。セッションの中身を Cookie そのものに入れて持たせている SP は、サーバ側から特定のセッションを消せないので、対応できません。

勤怠 SPメール SPIdPブラウザ勤怠 SPメール SPIdPブラウザここからはブラウザを通らないサーバ間通信未対応の勤怠のセッションは寿命まで残るログアウトSSO セッションの Cookie を消すログアウトトークン・セッション ID該当するアプリセッションを削除200 OKログアウトトークン404 受け口がない

どちらの方式も、すべての SP が対応していなければ穴が残ります。実務では、SP のアプリセッションを短めにして IdP へこまめに確認させる(そのたびに IdP 側の停止が効く)、重要な操作の前に再認証を求める、アカウントの削除を SCIM(後述)で各 SP へ同期する、といった手段を組み合わせて近似します。さらに一歩進んだ仕組みとして、IdP と SP が「このアカウントが停止された」「このセッションを取り消した」といった出来事をリアルタイムに伝え合う、OpenID の Shared Signals Framework(CAEP)の採用も進んでいます。

プロトコルと周辺概念

認証結果の受け渡しに使う標準は、XML ベースの SAML と、OAuth 2.0 の上に認証を載せた OIDC です。エンタープライズの SaaS 連携では SAML が長い実績を持ち、新しく作るシステムや、モバイルアプリ・API を含む構成では、JSON と OAuth の土台を持つ OIDC が選ばれる傾向にあります。Okta・Microsoft Entra ID・Google Workspace・Keycloak といった IdP 製品は両方に対応していて、SP の対応状況に合わせて使い分けます。

SSO と混同されやすいものに、認証のあとで「何をしてよいか」を決める認可があります。SSO が担うのは「誰か」を確かめて各 SP に伝えるところまでで、権限の管理は RBAC などの各サービス側の仕組みと組み合わせます。IdP のグループ情報を認証結果に載せ、SP 側でロールに対応づける形がよく使われます。また、アカウントの作成・更新・削除を IdP から各 SP へ自動で同期する SCIM(System for Cross-domain Identity Management)は、SSO とセットで導入されることの多い隣接技術です。SSO は「ログインの入口」を一つにしますが、各 SP の中に作られたアカウントそのものを消すのは SCIM の役目です。

設計上のトレードオフ

認証を一箇所に集めることは、単一障害点を一箇所に集めることでもあります。IdP が止まれば新しいログインがすべてできなくなり、IdP のアカウントが乗っ取られれば全サービスに芋づる式に入られます。だからこそ IdP には MFA の強制、端末や場所を見るリスクベース認証、厳重な監視といった最高水準の防御を集中させます。IdP の障害に備えて、SSO を通らずに入れる緊急用の管理者アカウントを金庫にしまっておく運用も一般的です。

セッションの寿命の決め方にもトレードオフがあります。SP のセッションを長くすれば、利用者は快適で IdP への負荷も減りますが、IdP での停止が届くまでの時間も延びます。短くすれば停止はすぐ効きますが、IdP を往復する回数が増え、IdP が止まったときの影響も早く広がります。守るべき場所を一箇所に絞って徹底的に固め、そのうえで各サービスの寿命を重要度に応じて決める。この考え方は、アクセスのたびに検証を求めるゼロトラストでも、IdP を中核に据える形で受け継がれています。

試問

会社の認証窓口(IdP)と、メール(セッションの寿命12時間)・チャット(24時間)・勤怠(2時間)の3つのサービスがあります。下のタブでサービスを開いてログインし、IdP でアカウントを停止できます。「IdP → SP の通知」で、IdP から各サービスへ直接知らせるかどうかを選べ、時計は早送りできます。退職する社員を、できるだけ早く全サービスから締め出す場面です。

✦ 命題挑戦中

退職する社員のアカウントを停止してから3時間以内に、3つのサービスすべてから締め出せ

  • 3つのサービスすべてに入った状態で、アカウントを停止する
  • 停止のあと、どのサービスのセッションも残っていない
  • それが停止から3時間以内(時計の経過で)
⚡ 体験: SSO のセッションを二層で確かめる
サーバの世界 — IdP と SP はふだん直接は話さないブラウザの世界破線=リダイレクト認証結果はブラウザが運ぶ直通の経路なし(信頼は事前の設定だけ)IdPSSO セッションなしメールセッションなしチャットセッションなし勤怠セッションなしブラウザCookie はドメイン別メールチャット勤怠ブラウザの Cookie — ドメインごとに別の引き出し(バーの長さ=寿命、同じ縮尺)経過 0秒第1層第2層idp.example | SSO セッション(まだない)mail.example | メールのアプリセッション(まだない)chat.example | チャットのアプリセッション(まだない)kintai.example | 勤怠のアプリセッション(まだない)
時計
IdP → SP の通知
見つけたこと 0/4 — 次は「最初だけログイン」
あなたの操作から描かれるシーケンス図(直近12行)
ブラウザIdPメールチャット勤怠まだ何も起きていません

下のブラウザのタブ「メール」を押して開いてください。まだどこにもログインしていません。