【押さえておきたい】OAuth 2.0とOpenID ConnectとFAPI 2.0の概要
はじめに
いくつかの仕事のなかで、つぎの技術を採用しました。
- OAuth 2.0
- OpenID Connect
- FAPI 2.0(Financial-grade API)
仕様の理解を進めるなかで、つぎの課題を感じたため、
初級者や中級者の助けになればと、この記事を書くことにしました。
- OAuth 2.0 / OpenID Connect
- 日本語の情報も多いですが、中級者向けの情報は少ない。
- FAPI 2.0
- 日本語や英語を問わず、情報が少ない。
OAuth 2.0
HTTPのAPIを前提にした、認可のフレームワークである。
APIを呼び出すときに、
パスワードを送信するのではなく、
アクセストークンを送信することで、
セキュリティを向上しつつ、アクセス権を柔軟に制御できる。
アクセストークンの送信には、HTTP Headerが利用されることが多い。
GET /resource/123 HTTP/1.1
Host: server.example.com
Authorization: Bearer mF_9.B5f-4.1J
RFC 6749: The OAuth 2.0 Authorization Framework 日本語訳
RFC 6750: The OAuth 2.0 Authorization Framework: Bearer Token Usage 日本語訳
Access Token
アクセスの期間や範囲を示す、文字列である。
Roles
4つの登場人物が中心になる。
Roles | Description |
---|---|
リソースオーナー | リソースへのアクセスを認可するもの。 基本的には、エンドユーザーが該当する。 Client Credentialsでは、クライアントが該当する。 |
リソースサーバー | リソースを提供するもの。 アクセストークンを検証したあと、APIのレスポンスでリソースを提供する。 |
クライアント | リソースオーナーの認可を得て、リソースを要求するもの。 アクセストークンを送信しつつ、APIのリクエストでリソースを要求する。 サーバー上で動く、ウェブアプリのこともあれば、 デバイス上で動く、スマートフォンアプリのこともある。 |
認可サーバー | リソースオーナーの認証と認可を確認したあと、 クライアントにアクセストークンを発行するもの。 |
Client Type
クライアントは2種類に分類される。
Client Type | Description |
---|---|
コンフィデンシャル | クレデンシャルの機密性を維持することができるもの。 または、セキュアなクライアント認証ができるもの。 サーバー上で動く、ウェブアプリなど。 |
パブリック | クレデンシャルの機密性を維持することができず、 セキュアなクライアント認証もできないもの。 デバイス上で動く、スマートフォンアプリなど。 |
Grant Type
4つのグラントタイプがある。
- Authorization Code
- Implicit
- Resource Owner Password Credentials
- Client Credentials
グラントタイプごとに、処理の流れが異なる。
それぞれに特徴があるため、
ユースケースに合わせて、グラントタイプを選択することになる。
Authorization Code
代表的なグラントタイプである。
リダイレクトを利用するため、
クライアントはユーザーエージェント(WebBrowser)と対話できなければならない。
+----------+
| Resource |
| Owner |
| |
+----------+
^
|
(B)
+----|-----+ Client Identifier +---------------+
| -+----(A)-- & Redirection URI ---->| |
| User- | | Authorization |
| Agent -+----(B)-- User authenticates --->| Server |
| | | |
| -+----(C)-- Authorization Code ---<| |
+-|----|---+ +---------------+
| | ^ v
(A) (C) | |
| | | |
^ v | |
+---------+ | |
| |>---(D)-- Authorization Code ---------' |
| Client | & Redirection URI |
| | |
| |<---(E)----- Access Token -------------------'
+---------+ (w/ Optional Refresh Token)
処理の流れ
(A)
クライアントがユーザーエージェントを、認可サーバーの認可エンドポイントに送る。
この認可リクエストには、クライアント識別子やリダイレクトURIが含まれる。
(B)
認可サーバーはリソースオーナーを認証したあと、リソースオーナーに認可を求める。
(C)
リソースオーナーが認可をすると、ユーザーエージェントはクライアントにリダイレクトされる。
リダイレクトするとき、クエリパラメータに認可コードなどを付加する。
このリダイレクトを認可レスポンスと呼ぶ。
(D)
クライアントは、認可サーバーのトークンエンドポイントを呼び出す。
このアクセストークンリクエストには、認可コードやリダイレクトURIが含まれる。
(E)
認可サーバーは認可コードなどを検証したあと、アクセストークンを返却する。
このアクセストークンレスポンスには、リフレッシュトークンを含んでもよい。
Implicit
Authorization Codeを単純化した、グラントタイプである。
通信回数が減るため、処理効率を高めることができるが、
特定条件下で攻撃が成立するため、利用には注意したほうがよい。
リダイレクトを利用するため、
クライアントはユーザーエージェント(WebBrowser)と対話できなければならない。
+----------+
| Resource |
| Owner |
| |
+----------+
^
|
(B)
+----|-----+ Client Identifier +---------------+
| -+----(A)-- & Redirection URI --->| |
| User- | | Authorization |
| Agent -|----(B)-- User authenticates -->| Server |
| | | |
| |<---(C)--- Redirection URI ----<| |
| | with Access Token +---------------+
| | in Fragment
| | +---------------+
| |----(D)--- Redirection URI ---->| Web-Hosted |
| | without Fragment | Client |
| | | Resource |
| (F) |<---(E)------- Script ---------<| |
| | +---------------+
+-|--------+
| |
(A) (G) Access Token
| |
^ v
+---------+
| |
| Client |
| |
+---------+
処理の流れ
(A)
クライアントがユーザーエージェントを、認可サーバーの認可エンドポイントに送る。
この認可リクエストには、クライアント識別子やリダイレクトURIが含まれる。
(B)
認可サーバーはリソースオーナーを認証したあと、リソースオーナーに認可を求める。
(C)
リソースオーナーが認可をすると、ユーザーエージェントはクライアントにリダイレクトされる。
リダイレクトするとき、フラグメントにアクセストークンなどを付加する。
このリダイレクトをアクセストークンレスポンスと呼ぶ。
(D)
ウェブアプリがホスティングされる、サーバーにリクエストを送信する。
(E)
サーバーのレスポンスで、スクリプトが返却される。
(F)
ユーザーエージェントはスクリプトを実行し、アクセストークンを取り出す。
(G)
ユーザーエージェントはアクセストークンをクライアントに渡す。
Resource Owner Password Credentials
エンドユーザーのパスワードなど、
クレデンシャルをクライアントに直接に入力する、グラントタイプである。
クライアントの信頼性が高いうえ、
ほかのグラントタイプが利用できないときに、利用されるべきである。
パスワードがクライアントに露呈してしまうが、
アクセストークンと交換するため、長期的な保存の必要はなくなる。
+----------+
| Resource |
| Owner |
| |
+----------+
v
| Resource Owner
(A) Password Credentials
|
v
+---------+ +---------------+
| |>--(B)---- Resource Owner ------->| |
| | Password Credentials | Authorization |
| Client | | Server |
| |<--(C)---- Access Token ---------<| |
| | (w/ Optional Refresh Token) | |
+---------+ +---------------+
処理の流れ
(A)
リソースオーナーがクライアントにパスワードを入力する。
(B)
クライアントは、認可サーバーのトークンエンドポイントを呼び出す。
このアクセストークンリクエストには、パスワードが含まれる。
(C)
認可サーバーはパスワードなどを検証したあと、アクセストークンを返却する。
このアクセストークンレスポンスには、リフレッシュトークンを含んでもよい。
Client Credentials
クライアントのパスワードなど、
クレデンシャルを直接に送信する、グラントタイプである。
クライアントがリソースオーナーとなり、
クライアントの権限でリソースを要求する。
クライアントの権限でリソースを要求するか、
エンドユーザーの権限でリソースを要求するか、
ほかのグラントタイプとは、認可の種類が異なる。
コンフィデンシャルクライアントにだけ、適用できる。
+---------+ +---------------+
| | | |
| |>--(A)- Client Authentication --->| Authorization |
| Client | | Server |
| |<--(B)---- Access Token ---------<| |
| | | |
+---------+ +---------------+
処理の流れ
(A)
クライアントは、認可サーバーのトークンエンドポイントを呼び出す。
このアクセストークンリクエストには、クライアントのクレデンシャルが含まれる。
(B)
認可サーバーはクレデンシャルなどを検証したあと、アクセストークンを返却する。
OpenID Connect
OAuth 2.0をベースにした、認証のフレームワークである。
OAuth 2.0では、アクセストークンが発行されるが、
OpenID Connectでは、IDトークンが発行される。
実際には、アクセストークンとIDトークンは同時に発行されることが多い。
IDトークンを検証することで、エンドユーザーの認証(本人確認)ができる。
ID Token
認証情報が含まれる、文字列である。
IDトークンの形式はJWTである。
このJWTには、各種の情報が含まれるが、
代表例として、つぎのクレームが含まれている。
Claim | Description |
---|---|
iss | IDトークンの発行者 |
sub | エンドユーザーの識別子 |
aud | IDトークンの発行先 |
exp | IDトークンの有効期限 |
iat | IDトークンの発行時刻 |
{
"iss": "https://server.example.com",
"sub": "24400320",
"aud": "s6BhdRkqt3",
"exp": 1311281970,
"iat": 1311280970,
...
}
IDトークンに署名は必須だが、暗号化は任意である。
Roles
3つの登場人物が中心になる。
Roles | Description |
---|---|
End-User | エンドユーザー。 OAuth 2.0のリソースオーナーに相当する。 |
Relying Party | IDトークンを要求するもの。 OAuth 2.0のクライアントに相当する。 |
OpenID Provider | エンドユーザーの認証と認可を確認したあと、 Relying PartyにIDトークンを発行するもの。 OAuth 2.0の認可サーバーに相当する。 |
Authentication Flow(Grant Type)
3つの認証フローがある。
- Authorization Code
- Implicit
- Hybrid
認証フローごとに、処理の流れが異なる。
それぞれに特徴があるため、
ユースケースに合わせて、認証フローを選択することになる。
OAuth 2.0とOpenID Connectで、流れに違いはない。
Authorization CodeとImplicitを組み合わせたものが、Hybridである。
Client Authentication
5つのクライアント認証がある。
- client_secret_basic
- client_secret_post
- client_secret_jwt
- private_key_jwt
- none
それぞれに特徴があるため、
ユースケースに合わせて、クライアント認証を選択することになる。
トークンエンドポイントを呼び出すときなどに利用する。
FAPI 2.0
OAuth 2.0をベースにした、セキュリティプロファイルである。
金融など、高いセキュリティが求められるAPIに適している。
セキュリティプロファイルには、
つぎのチェックリストや技術仕様が含まれており、
適用することで、OAuth 2.0とOpenID Connectの安全性を向上できる。
Specification | Description |
---|---|
FAPI 2.0 Security Profile | Attacker Modelの目標を達成するためのチェックリスト。 BaselineからSecurity Profileに名称が変更された。 つまり、Baselineに相当の仕様である。 |
FAPI 2.0 Attacker Model | |
FAPI 2.0: Message Signing | 認可サーバーへのリクエストとレスポンスに署名する。 AdvancedからMessage Signingに名称が変更された。 つまり、Advancedに相当の仕様である。 |
FAPI 2.0 Http Signatures | リソースサーバーへのリクエストとレスポンスに署名する。 RFC 9421をベースにしている。 |
FAPI 2.0 Security Profile
チェックリストの項目は100に近い。
HTTPでユーザーエージェントをリダイレクトするとき、
307ではなく、303のステータスコードを利用するなど、
単純なチェックリストもあるが、
RFC 9126に従い、Pushed Authorization Requestsをサポートするなど、
複雑なチェックリストもある。
ここでは代表例を紹介する。
Client Type
Confidential Clientに制限されている。
Sender-Constrained Access Token
つぎのいずれかの方法で、
送信者制約アクセストークンを発行することが求められる。
- MTLS(RFC 8705)
- DPoP(RFC 9449)
Client Authentication
つぎのいずれかの方法で、
クライアント認証を実施することが求められる。
- MTLS(RFC 8705 - Section 2)
- private_key_jwt(OIDC - Section 9)
Pushed Authorization Request
RFC 9126に従い、
Pushed Authorization Request(PAR)を実施することが求められる。
FAPI 2.0 Security Profileの処理の流れ
Sender-Constrained Access TokenとClient Authenticationに、
MTLSを採用と仮定すると、つぎの処理の流れになる。
Discussion