OAuthとは ― 認可の仕組みとOIDCとの違い
OAuthは、
OAuthとは、パスワードを渡さずにアプリへ権限を渡す仕組み
OAuthは、利用者のパスワードをアプリに渡さずに、範囲と期限を決めた権限だけをアプリに与える仕組みです。アプリを連携するときに、写真や予定へのアクセスを許すかを尋ねる同意画面が出ます。この画面が、OAuthで権限を渡す手順の一部です。
許可すると、アプリはパスワードの代わりにアクセストークンを受け取ります。アプリは、これを見せてデータを使います。いま使われているのは、2012年にインターネットの技術仕様RFC 6749で定められたOAuth 2.0です。
OAuthが受け持つのは、アプリに何をしてよいかを決める認可です。利用者が誰かをアプリに伝える認証は、後の節で説明するOpenID Connectが受け持ちます。
パスワードを預ける連携との違い
RFC 6749は、印刷サービスが写真サービスの写真を使う例を挙げています。OAuthが無ければ、利用者は写真サービスのIDとパスワードを、印刷サービスに預けることになります。
RFC 6749の1節は、この預け方の問題を挙げています。印刷サービスは、パスワードを保存し続けます。印刷サービスは写真をすべて見られ、範囲も期間も絞れません。
印刷サービスだけを止めたくても、パスワードを変えるしかありません。印刷サービスが攻撃で破られると、パスワードも、そのパスワードで守っていたデータも漏れます。
OAuthでは、利用者は写真サービス側の認可サーバにだけパスワードを入れます。印刷サービスが受け取るのは、範囲と期限が決まった権限を表す文字列です。この文字列を、アクセストークンと呼びます。
アプリが利用者のパスワードを受け取り、それをアクセストークンに換える方式も、RFC 6749には残っています。2025年のRFC 9700は、パスワードがアプリに渡ってしまうため、この方式を使ってはならないとしています。
認証と認可の違い
認証は相手が誰かを確かめること、認可は確かめた相手に何をしてよいかを決めることです。ログインでパスワードを確かめるのは、認証です。そのあと、写真の読み取りだけを許すと決めるのは、認可です。
多要素認証で組み合わせる記憶・所持・生体の3要素は、認証を強くする手段です。RADIUSも、認証と認可を分けて扱います。
OAuthは、認可の仕組みです。認可サーバは、権限を渡す前に利用者を認証します。ただし、その結果をアプリに伝える方法は、OAuth 2.0では決めていません。RFC 6749は、アプリに対する利用者の認証を、仕様の範囲外としています。
OAuthの4つの役割
RFC 6749の1.1節は、OAuthに登場する役割を4つ定めています。印刷の例に当てはめると、次のようになります。
| 役割 | 印刷の | する |
|---|---|---|
| リソースオーナー | 利用者 | 自分の |
| クライアント | 印刷サービス | 利用者の |
| 認可サーバ | 写真サービス側の | 利用者を |
| リソースサーバ | 写真サービス | アクセストークンを |
クライアントは、データを使うアプリのことです。サーバで動くWebアプリも、スマホのアプリも、クライアントになれます。認可サーバとリソースサーバは、同じサーバでも別のサーバでもかまいません。
認可コードフローの流れ
クライアントがアクセストークンを受け取る手順は、いくつか決まっています。中心になるのは、認可コードを経由する手順です。RFC 6749は4.1節でこの手順を定め、認可コードグラントと呼んでいます。一般には認可コードフローとも呼ばれます。
ブラウザを通るのは、①の認可リクエストと③の認可コードです。アクセストークンは、④と⑤で、クライアントと認可サーバが直接やり取りして受け渡します。RFC 6749は、この方式の利点を2つ挙げています。アクセストークンがブラウザを通らないことと、④でクライアントを認証できることです。
認可コードは、ブラウザを通るので漏れることがあります。そのため、RFC 6749は認可コードを1回しか使えないものとしています。期限も、最長10分にするよう勧めています。
スコープで範囲を、有効期限で期間を絞る
クライアントは、①の要求のscopeで、求める権限の範囲を伝えます。範囲を表す値は、認可サーバが決めます。図のphoto.readは、写真の読み取りを表す例として作った値です。
RFC 6749は、クライアントに、必要最小限の範囲だけを求めるよう勧めています。認可サーバは、求められた範囲より狭い権限で発行してもかまいません。
アクセストークンの有効期間は、⑤のexpires_inで、秒数として伝えます。RFC 6750は、漏れたときの影響を小さくするため、1時間以内の短い期限で発行するよう勧めています。
動かして確かめる:認可コードフローを1段ずつ進める
次の図は、前の図の6段を1段ずつ示します。段ごとに、送る側と受け取る側の役割が光り、渡る値と渡らないものが分かります。
利用者のパスワードが出てくるのは②だけで、入力する相手は認可サーバです。印刷サービスが受け取るのは、認可コードとアクセストークンです。
アクセストークンとリフレッシュトークン
アクセストークンは、リソースサーバに見せてデータを使うための値です。多くのリソースサーバは、Web APIとしてデータを渡します。RFC 6750が定める送り方では、Authorization: Bearerのあとにトークンを続けます。
Bearerは、持っている人を表す英語です。RFC 6750は、持っていれば誰でも使えるトークンとして定義しています。そのため、漏らさないことを第一の注意点とし、送るときは必ずTLSを使うよう求めています。
RFC 6750は、トークンをページのURLに入れないことも勧めています。URLは、ブラウザの履歴やサーバのログに残るからです。持っているだけで使える点は、CookieのセッションIDと同じです。
リフレッシュトークンは、新しいアクセストークンを受け取るための値です。アクセストークンが期限切れになると、クライアントはこれを認可サーバに送ります。認可サーバは確かめたうえで、新しいアクセストークンを返します。
| 比べる | アクセストークン | リフレッシュトークン |
|---|---|---|
| 使い道 | データを | 新しい |
| 送る | リソースサーバ | 認可サーバだけ |
| 発行 | 必ず | 発行するかは |
RFC 6749は、リフレッシュトークンをリソースサーバに送らないものとしています。秘密の値を安全に保てないアプリを、公開クライアントと呼びます。スマホのアプリやブラウザで動くアプリが、その例です。RFC 9700は、公開クライアントのリフレッシュトークンを、使うたびに新しいものに替えるなどの方法で守るよう求めています。
認可コードの横取りとPKCE
スマホのアプリでは、③で戻ってくる認可コードを、別のアプリに横取りされることがあります。RFC 7636によると、悪意のあるアプリが、正規のアプリと同じ独自のURIスキームを登録して受け取ります。URIスキームは、アプリを開くURLの先頭部分です。認可コードを手に入れた攻撃者は、それをアクセストークンと引き換えられます。
この横取りを防ぐのが、PKCEです。PKCEはProof Key for Code Exchangeの略です。RFC 7636は、ピクシーと読むとしています。
- クライアントは、認可リクエストのたびに、code_verifierという乱数を作ります。
- ①では、その乱数のSHA-256によるハッシュ値を、code_challengeとして送ります。
- ④では、元の乱数のcode_verifierを送ります。
- 認可サーバは、届いた乱数のハッシュ値を計算し、①の値と一致したときだけトークンを返します。
横取りした攻撃者は、元の乱数を知りません。ハッシュ値から元の値を求められないのは、ハッシュ関数の性質です。そのため、認可コードだけを手に入れても、アクセストークンを受け取れません。
PKCEは、もともとスマホのアプリを守るために作られました。RFC 9700は、公開クライアントにPKCEを必須とし、Webアプリにも使うよう勧めています。
stateで、戻り先へのCSRFを防ぐ
攻撃者は、自分の認可コードを付けた③の要求を、利用者のブラウザに送らせることもできます。成功すると、利用者の印刷サービスが、攻撃者の写真サービスのアカウントにつながります。RFC 6749は、これをCSRFの一種として挙げています。
クライアントは、①でstateという推測できない値を送ります。この値は、ブラウザのセッションと結び付けて覚えておきます。③で戻ってきたstateが一致しなければ、処理しません。RFC 9700は、PKCEに対応した認可サーバが相手なら、PKCEでもこの攻撃を防げるとしています。
インプリシットフローが勧められなくなった理由
インプリシットフローは、認可コードを使わずに、認可の応答で直接アクセストークンを渡す方式です。RFC 6749は、ブラウザ上のJavaScriptで動くアプリ向けに、手順を減らした方式として定めました。
この方式では、アクセストークンがURLのフラグメントに入って、ブラウザに渡ります。フラグメントは、URLの#から後ろの部分です。RFC 6749も、ここから第三者にトークンが漏れうると注意していました。
RFC 9700は、インプリシットフローを、トークンの漏えいと使い回しに弱い方式としています。トークンを特定のクライアントに結び付ける標準の方法も、この方式にはありません。そのため、トークンの差し込みと漏えいを防げない限り、使うべきではないとしています。代わりに認可コードフローを使うよう勧めています。
ブラウザで動くアプリは、公開クライアントにあたります。RFC 9700に従うと、PKCEを付けた認可コードフローを使います。
OAuthとOpenID Connect(OIDC)の違い
OpenID Connectは、OAuth 2.0の上に、利用者が誰かを伝える仕組みを足した規格です。OpenID Foundationが定め、中心の仕様をOpenID Connect Core 1.0と呼びます。仕様は、OAuth 2.0だけでは利用者の認証についての情報を伝えられないと説明しています。
OIDCを使うときは、①のscopeにopenidを含めます。すると、認可サーバは⑤で、アクセストークンと一緒にIDトークンを返します。IDトークンは、認証の結果を書いたデータで、JWTという形式で表します。
| 比べる | OAuth 2.0 | OpenID Connect |
|---|---|---|
| 受け持つこと | アプリに | 利用者が |
| アプリが | アクセストークン | IDトークンと |
| 受け取った | リソースサーバ | IDトークンは |
| 定める | IETF | OpenID Foundation |
IDトークンには署名が付いています。中には、発行した認可サーバ・利用者の識別子・宛先のアプリ・有効期限などの項目が必ず入ります。アプリは、宛先に自分が含まれることや、発行元と有効期限などを確かめてから利用者を受け入れます。AWSでは、Amazon Cognitoのユーザープールが、IDトークンとアクセストークンを発行する役を受け持ちます。
アクセストークンを受け取れたことを、ログインの証拠にするのは危険です。RFC 6749によると、インプリシットフローでは、トークンがどのアプリあてに発行されたかをアプリが確かめられません。そのため、トークンを持ってくれば本人だと考える公開クライアントは、他人のトークンでなりすまされると注意しています。
シングルサインオンでは、IdPが認証の結果をアサーションとしてRPに伝えます。OIDCのIDトークンは、このアサーションの形式の1つです。
同意画面で確かめること
同意画面では、どのアプリに、どの範囲を許すのかを確かめます。RFC 6749は、利用者がだまされて、攻撃者のアプリに自分から権限を渡してしまう場合を挙げています。アプリの求める範囲が、使いたい機能より広すぎないかも見ます。
パスワードを入れる画面が、そのサービスの画面かも確かめます。RFC 9700は、認可サーバ以外の場所でパスワードを入れる習慣が付くことを、パスワードを渡す方式の問題に挙げています。
練習問題(全7問)
正解:利用者の
OAuthでは、
正解:認証は
パスワードで
正解:認可サーバ
認可サーバは、
正解:認可サーバ
利用者は
正解:戻ってくる
PKCEでは、
正解:アクセストークンが
インプリシットフローは、
正解:IDトークン
OpenID Connectは、
選んでから「採点する」を押すと、解説つきで答え合わせができます。
参考にした資料
- RFC 6749 The OAuth 2.0 Authorization Framework(4つの役割、認可コードフロー、インプリシット、トークン、CSRFとstate)
- RFC 6750 Bearer Token Usage(Bearerの意味、トークンの送り方と守り方)
- RFC 7636 Proof Key for Code Exchange by OAuth Public Clients(認可コードの横取りとPKCE)
- RFC 9700 Best Current Practice for OAuth 2.0 Security(PKCEの必須化、インプリシットとパスワードを渡す方式の扱い)
- OpenID Connect Core 1.0(IDトークンとその確かめ方)
関連記事
おすすめの本 PR
セキュリティとデータベースは、基本情報技術者試験の対策本でまとめて学べます。

