ITの教科書検索

OAuthとは、パスワードを渡さずにアプリへ権限を渡す仕組み

OAuthは、利用者のパスワードをアプリに渡さずに、範囲と期限を決めた権限だけをアプリに与える仕組みです。アプリを連携するときに、写真や予定へのアクセスを許すかを尋ねる同意画面が出ます。この画面が、OAuthで権限を渡す手順の一部です。

許可すると、アプリはパスワードの代わりにアクセストークンを受け取ります。アプリは、これを見せてデータを使います。いま使われているのは、2012年にインターネットの技術仕様RFC 6749で定められたOAuth 2.0です。

OAuthが受け持つのは、アプリに何をしてよいかを決める認可です。利用者が誰かをアプリに伝える認証は、後の節で説明するOpenID Connectが受け持ちます。

パスワードを預ける連携との違い

RFC 6749は、印刷サービスが写真サービスの写真を使う例を挙げています。OAuthが無ければ、利用者は写真サービスのIDとパスワードを、印刷サービスに預けることになります。

パスワードを預ける連携利用者印刷サービス写真サービスID・パスワードID・パスワード範囲:すべての写真期限:決められない漏れると:パスワードも漏れるOAuthでの連携利用者認可サーバ印刷サービス写真サービスパスワード・同意アクセストークンアクセストークン範囲:写真の読み取りだけ期限:例えば1時間漏れても:パスワードは漏れない
パスワードを預ける連携と、OAuthでの連携を並べました。赤の矢印では利用者のパスワードが印刷サービスに渡り、橙の矢印ではアクセストークンだけが渡ります。色の枠の認可サーバは、OAuthの側にだけあります。

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節でこの手順を定め、認可コードグラントと呼んでいます。一般には認可コードフローとも呼ばれます。

リソースオーナー利用者とブラウザクライアント印刷サービス認可サーバ写真サービス側リソースサーバ写真サービス① 移動の指示認可リクエスト② パスワード入力と同意③ 認可コード認可コード④ 認可コード⑤ アクセストークン⑥ アクセストークン写真のデータブラウザが中継する移動アクセストークンが通る利用者=リソースオーナー印刷サービス=クライアント写真サービス=リソースサーバブラウザが中継する移動① 認可リクエスト印刷サービス認可サーバ渡るもの:client_id・scope・state② ログインと同意利用者認可サーバ渡るもの:パスワードと同意③ 認可コード認可サーバ印刷サービス渡るもの:認可コード・state④ 認可コードを渡す印刷サービス認可サーバ渡るもの:認可コード⑤ アクセストークン認可サーバ印刷サービス渡るもの:アクセストークン⑥ 写真を受け取る印刷サービス写真サービス渡るもの:アクセストークン返るもの:写真のデータ
矢印は、送る側から受け取る側へ向いています。点線の①と③は、ブラウザが中継する移動です。色の付いた⑤と⑥でアクセストークンが渡り、ブラウザは通りません。パスワードが出てくるのは②だけで、相手は認可サーバです。

ブラウザを通るのは、①の認可リクエストと③の認可コードです。アクセストークンは、④と⑤で、クライアントと認可サーバが直接やり取りして受け渡します。RFC 6749は、この方式の利点を2つ挙げています。アクセストークンがブラウザを通らないことと、④でクライアントを認証できることです。

認可コードは、ブラウザを通るので漏れることがあります。そのため、RFC 6749は認可コードを1回しか使えないものとしています。期限も、最長10分にするよう勧めています。

スコープで範囲を、有効期限で期間を絞る

クライアントは、①の要求のscopeで、求める権限の範囲を伝えます。範囲を表す値は、認可サーバが決めます。図のphoto.readは、写真の読み取りを表す例として作った値です。

RFC 6749は、クライアントに、必要最小限の範囲だけを求めるよう勧めています。認可サーバは、求められた範囲より狭い権限で発行してもかまいません。

アクセストークンの有効期間は、⑤のexpires_inで、秒数として伝えます。RFC 6750は、漏れたときの影響を小さくするため、1時間以内の短い期限で発行するよう勧めています。

動かして確かめる:認可コードフローを1段ずつ進める

次の図は、前の図の6段を1段ずつ示します。段ごとに、送る側と受け取る側の役割が光り、渡る値と渡らないものが分かります。

STEP 1 / 6
① 認可リクエスト
リソースオーナー利用者とブラウザブラウザが中継
クライアント印刷サービス送る
認可サーバ写真サービス側受け取る
リソースサーバ写真サービス
やり取り:印刷サービス → ブラウザ → 認可サーバ
GET https://auth.example.com/authorize
response_type=code
client_id=s6BhdRkqt3
redirect_uri=https://print.example.net/cb
scope=photo.read
state=xyz
渡らないもの:利用者のパスワード
利用者が印刷サービスで写真の読み込みを選ぶと、印刷サービスはブラウザを認可サーバへ移動させます。移動先のURLには、印刷サービスの識別子、戻り先、求める範囲が付きます。stateは、戻ってきた要求が同じブラウザからのものかを確かめる値です。

利用者のパスワードが出てくるのは②だけで、入力する相手は認可サーバです。印刷サービスが受け取るのは、認可コードとアクセストークンです。

アクセストークンとリフレッシュトークン

アクセストークンは、リソースサーバに見せてデータを使うための値です。多くのリソースサーバは、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は、ピクシーと読むとしています。

  1. クライアントは、認可リクエストのたびに、code_verifierという乱数を作ります。
  2. ①では、その乱数のSHA-256によるハッシュ値を、code_challengeとして送ります。
  3. ④では、元の乱数のcode_verifierを送ります。
  4. 認可サーバは、届いた乱数のハッシュ値を計算し、①の値と一致したときだけトークンを返します。

横取りした攻撃者は、元の乱数を知りません。ハッシュ値から元の値を求められないのは、ハッシュ関数の性質です。そのため、認可コードだけを手に入れても、アクセストークンを受け取れません。

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.0OpenID Connect
受け持つことアプリに権限を渡す認可利用者が誰かを伝える認証
アプリが受け取るものアクセストークンIDトークンとアクセストークン
受け取ったものを読む側リソースサーバIDトークンはアプリ自身が確かめる
定める団体IETF(RFC 6749)OpenID Foundation

IDトークンには署名が付いています。中には、発行した認可サーバ・利用者の識別子・宛先のアプリ・有効期限などの項目が必ず入ります。アプリは、宛先に自分が含まれることや、発行元と有効期限などを確かめてから利用者を受け入れます。AWSでは、Amazon Cognitoのユーザープールが、IDトークンとアクセストークンを発行する役を受け持ちます。

アクセストークンを受け取れたことを、ログインの証拠にするのは危険です。RFC 6749によると、インプリシットフローでは、トークンがどのアプリあてに発行されたかをアプリが確かめられません。そのため、トークンを持ってくれば本人だと考える公開クライアントは、他人のトークンでなりすまされると注意しています。

シングルサインオンでは、IdPが認証の結果をアサーションとしてRPに伝えます。OIDCのIDトークンは、このアサーションの形式の1つです。

同意画面で確かめること

同意画面では、どのアプリに、どの範囲を許すのかを確かめます。RFC 6749は、利用者がだまされて、攻撃者のアプリに自分から権限を渡してしまう場合を挙げています。アプリの求める範囲が、使いたい機能より広すぎないかも見ます。

パスワードを入れる画面が、そのサービスの画面かも確かめます。RFC 9700は、認可サーバ以外の場所でパスワードを入れる習慣が付くことを、パスワードを渡す方式の問題に挙げています。

練習問題(全7問)

Q1OAuthの説明として正しいものはどれ?
Q2認証と認可の違いとして正しいものはどれ?
Q3OAuthの4つの役割のうち、アクセストークンを発行するのはどれ?
Q4認可コードフローで、利用者がパスワードを入力する相手はどれ?
Q5PKCEが防ぐ攻撃として正しいものはどれ?
Q6インプリシットフローが勧められなくなった理由として正しいものはどれ?
Q7OpenID Connectで、アプリが利用者を確かめるために受け取るものはどれ?

選んでから「採点する」を押すと、解説つきで答え合わせができます。

参考にした資料

関連記事

おすすめの本 PR

セキュリティとデータベースは、基本情報技術者試験の対策本でまとめて学べます。

目的別の本の選び方を見る

セキュリティの記事を続けて読む

セキュリティ 全37本中23本目