本ブログ記事は 2023年12月22日 に公開された「OAuth 2.0 Security Enhancements」を機械翻訳した記事となります。
OAuth 2.0 は現在広く採用されていますが、いくつかのセキュリティの課題が残っています。最近、OAuth 2.0 のセキュリティを向上させ、これらの課題に対処するために新しい仕様が 2 つ公開されました。これらは「DPop (Demonstrating Proof of Possession)」と「ステップアップ認証チャレンジプロトコル」です。これらがどのように機能するのか、概要を紹介します。
DPoP (Demonstrating Proof of Possession)
OAuth 2.0 に関連する最も人気のある仕様はアクセストークンです。トークンおよびリフレッシュトークンは、ベアラートークンであり、使用方法の仕様が定められています。この仕様で言及されているように、ベアラートークンの基本的な特徴は、「トークンを所持するいかなる当事者(ベアラー)は、他の当事者でも所持している限り使用できる方法でそのトークンを使用できる」ということです。
この使用方法はトークン管理を簡素化するものですが、いくつかのセキュリティ上の懸念を引き起こします。実際、悪意のある者がアクセストークンを盗むことができれば、それを何の問題もなく使用することができます。そのため、潜在的な脅威を緩和するために、いくつかのセキュリティ対策を講じる必要があります。
詳細を知るために アクセス トークンと ID トークンの違いについて をお読みください
Demonstrating Proof of Possession (DPoP) は、アクセスまたはリフレッシュトークンを使用できる人を制限するための仕組みです。 このメカニズムによって、認可サーバーはリクエストしたクライアントに結び付けられたトークンを発行し、その特定のクライアント以外はアクセスまたはリフレッシュトークンを使用できなくなります。 言い換えれば、DPoP を使用して発行されたトークンは、もはやベアラートークンではありません。
DPoPアクセス トークンをリクエスト
DPoP を使用するクライアントは、トークンの正当な受信者であることを証明しなければなりません。これは公開鍵暗号方式を使用して行われます。クライアントは、公開鍵/秘密鍵ペアの秘密鍵を保有していることを証明しなければなりません。DPoP が標準の OAuth 2.0 フローでどのように機能するか理解するために、順を追って説明します。
説明のために、認可コードフロー を使用しますが、他のフローにも同様に適用されます。以下はステップの概略です:
- ユーザーはフローを開始する要求と共に認可サーバーにリダイレクトされます。
- 認可サーバはユーザを認証し、認可コードと共にアプリケーションにリダイレクトします。
- クライアントアプリケーションは公開鍵/秘密鍵ペアを生成し、公開鍵を含む JWT の DPoP Proof、HTTP リクエストのメソッドや URI を作成します。これにより、DPoP Proof が特定の HTTP リクエストに紐づけられます。
- クライアントアプリケーションはアクセス トークンを要求するために認可サーバに認可コードを送ります。HTTP リクエストには、
ヘッダに DPoP Proof が含まれます。以下は、DPoP証明を使用したアクセストークンリクエストの例です。:DPoP
POST /token HTTP/1.1 Host: server.example.com Content-Type: application/x-www-form-urlencoded DPoP: eyJhbGciOiJFUzI1NiIsInR5cCI6ImRwb3Arand0IiwiandrIjp7Imt0eSI6IkVDIiwiY3J2I... grant_type=authorization_code &code=3LgurgEWbtafaqTn2VxkASV &redirect_uri=https%3A%2F%2Fapp.example.com
- 認可サーバは、署名およびリクエストの詳細(HTTP メソッドと URI)を確認して DPoP プルーフを検証します。その後、クライアントの公開鍵のハッシュ(JWK thumbprint)を生成し、それをアクセストークンに組み込みます。非 JWT アクセストークンの場合、JWK thumbprint は インスペクションエンドポイント を通じて確認できます。最後に、認可サーバは、JWK thumbprint を持つアクセストークンをクライアントアプリケーションに送信します。
DPoP アクセストークンを使用する
クライアントアプリケーションが保護されたAPIを呼び出す必要がある場合、次のステップを実行します:
- クライアントアプリケーションは、これから行おうとしている HTTP リクエストに紐付けられた新しい DPoP Proof を作成します。
- クライアントは、HTTP リクエストの
ヘッダにAuthorization
スキーマを使用してアクセス トークンを送信します。また、DPoP
ヘッダにも DPoP プルーフを使用します。以下は、DPoP Proof を使用した API 呼び出しの例です。:DPoP
GET /protectedresource HTTP/1.1 Host: api.example.com Authorization: DPoP eyJhbGciOiJFUzI1NiIsInR5cCI6ImF0K0pXVCIsImNuZiI6eyJqa3QiOiJybW56aTJvSWNYW... DPoP: eyJhbGciOiJFUzI1NiIsInR5cCI6ImRwb3Arand0IiwiandrIjp7Imt0eSI6IkVDIiwiY3J2I...
- 標準的なアクセストークンの検証に加え、API は DPoP Proof も検証し、このリクエストが意図された送信者からのものであることを確認します。
DPoP を使用することにより、単純なベアラートークンよりも高いセキュリティが提供されますが、これは DPoP アクセス トークンに対する脅威がないことを意味するわけではありません。より詳細については DPoP 仕様についてのセキュリティ考慮事項 を確認ください。
ステップアップ認証チャレンジプロトコル
OAuth 2.0 の第2のセキュリティ強化として、ステップアップ認証チャレンジプロトコル仕様が導入されました。この仕様には Okta のVittorioとBrian Campbellが著者として関わっています。
この仕様はクライアントによってリスクのある操作が要求されたときに、より強力な認証要件を強制するために、OAuth 2.0 で保護された API にステップアップ認証を追加します。つまり、クライアントが重要な API エンドポイントを呼び出すと、サーバはアクセストークンが特定の認証要件を満たしているかどうかを確認し、満たしていない場合は、クライアントに何が必要かを示すエラー応答を返します。
ステップアップ認証のフロー
基本的なフローは以下のステップとなります:
- クライアントがアクセストークンを含むリクエストを重要な AP Iエンドポイントに送信します。
- API エンドポイントは、アクセストークンからユーザ認証に関する情報を取り出します。
- ユーザ認証情報がそのエンドポイントの認証要件を満たしている場合、リクエストは処理されます。要件を満たさない場合、API エンドポイントは認証要件を含むエラー応答を返します。
- クライアントは、認証要件を満たす新しいアクセストークンを認可サーバに要求します。
認証要件
仕様では、2 種類の認証要件を定義しています。:
- 認証コンテキストクラス (Authentication Context Class Reference, ACR): この要件は 1 つ以上の特定の認証方法を示します。例えば、多要素認証(MFA)が必要であることを指定できます。
- 最大認証時間 (Maximum Authentication Age): この要件は、最後のアクティブなユーザ認証からの経過時間を示します。アクティブなユーザ認証とは、ユーザが積極的に関与した時に発生します。例えば、ユーザー名とパスワードを入力する場合などです。まだ有効な認証済みセッションがあり暗黙の認証が行われても、アクティブなユーザ認証とはみなされません。
これらの要件は標準の
acr
および auth_time
クレームで、JWTアクセストークンに埋め込まれています。JWT以外のアクセストークンの場合、要件はイントロスペクションエンドポイントを通じて検証できます。サマリー
この記事では、2023年9月にリリースされたOAuth 2.0のセキュリティを向上させるための新しい仕様について、概要レベルの紹介を行いました。DPoP 仕様は、アクセストークンをそれを要求したクライアントアプリケーションに紐付ける仕組みを定義し、ベアラートークンに関連するリスクに対処します。ステップアップ認証チャレンジプロトコルは、重要なリソースにアクセスする際やクライアントがリスクのある操作を要求する際に、より厳格な認証要件を求める方法を定義しています。
About the author
Andrea Chiarelli
Principal Developer Advocate
I have over 20 years of experience as a software engineer and technical author. Throughout my career, I've used several programming languages and technologies for the projects I was involved in, ranging from C# to JavaScript, ASP.NET to Node.js, Angular to React, SOAP to REST APIs, etc.
In the last few years, I've been focusing on simplifying the developer experience with Identity and related topics, especially in the .NET ecosystem.