Edited at

世界最先端の API セキュリティー技術、実装者による『FAPI(Financial-grade API)』解説


はじめに

Financial-grade API、通称 FAPI(『ファピ』と読む)は、OpenID FoundationFinancial-grade API ワーキンググループが策定を担当している技術仕様だ。OAuth 2.0OpenID Connect(以降 OIDC)を基盤とし、より高いセキュリティー要件を定めているのが特徴で、金融業界などの高度なセキュリティーが求められる環境での使用を想定している。

最新版は 2018 年 10 月に承認された Implementer's Draft 第二版で、次の場所で Part 1 と Part 2 が公開されている。Part 1 は参照系 API のセキュリティープロファイル、Part 2 は更新系 API のセキュリティープロファイルだ。

2017 年 2 月と 7 月に承認された Implementer's Draft 第一版との差分がそれなりにあるので、FAPI 実装者は対応が必要である。

第二版の序文で、FAPI の構成要素の一つとして CIBA(『シーバ』と読む)が挙げられていることは注目に値する。CIBA は FAPI の Part 3 という扱いになっている。CIBA については次の解説記事を参照してほしい。

本記事は FAPI のセキュリティープロファイルについて解説する。


コラム: FAPI と Authlete 社

私が代表をつとめる Authlete 社(『オースリート』と読む)は、FAPI に対応した Authlete 2.0 の提供開始を 2018 年 7 月 24 日に発表した。最新版の Authlete 2.1 開発ブランチは、FAPI Implementer's Draft 第一版と第二版の差分にも対応済みで、また、JARM(後述)や CIBA の実装も含んでいる。FAPI の汎用ソリューションとしては世界最先端を走っていると言ってよい。

弊社のシニア・アーキテクトであるジョセフ・ヒーナンは、FAPI ワーキンググループで最も活発に活動している貢献者の一人で、仕様書に「Joseph Heenan (Authlete)」として名前が記載されている。また、経緯説明は省略するが、彼は、FAPI の公式互換性テストスイート(fapi-conformance-suite)の開発を担当する FinTechLabs.io 社の CTO も務めている。

このように、Authlete 社は FAPI の実装・仕様策定・公式テストに深くコミットしており、日本はもとより、世界でも有数の FAPI に関する知見を持っている企業である。

FAPI 仕様には、矛盾した記述や実装者視点で非現実的である要求事項が依然として残っていることもあり、第二版承認以降も議論と更新作業は続いている。その様子の一端はこの記事内でも紹介している。そのような状況であるため、仕様書の字面を追っているだけでは FAPI 対応は難しい。FAPI に本格的に取り組む場合は、FAPI ワーキンググループMODRNA ワーキンググループ(CIBA を扱うグループ)の議論にリアルタイムでついていかなければならず、実装時に生じた疑問や発見した問題点については、ワーキンググループと積極的に対話して解消していかなければならない。しかし当然、それにはかなりの労力が求められる。そういう活動に十分なリソースを避けない場合や、専門家のアドバイスがほしい場合、公式 FAPI 互換性テストスイートと最も連動している世界最先端の FAPI 実装を必要としている場合などは、弊社 info@authlete.com まで遠慮なくご連絡いただきたい。

【追記】2019 年 4 月 4 日

2019 年 4 月から OpenID Foundation が Financial-grade API 認証プログラムの正式運用を開始。真っ先に認証を取得したのは、Authlete 社と ForgeRock 社の二社。Authlete 社は Private Key だけでなく MTLS についても認証を取得している。

certified_fapi_ops_20190401.png


0. 前提知識


0.1. 基本仕様群

FAPI の仕様書は要求事項を簡潔に列挙する形式となっており、文量はそれほど多くない。その代わり、すらすら読むためにはかなりの前提知識が要求される。特に、OAuth 2.0 の中心となる RFC 6749RFC 6750、および OIDC の中心となる OpenID Connect Core 1.0(以降 OIDC Core)については、ほぼ頭に入っている必要がある。

また、OIDC Core を理解するための前提知識となる JWT 関連仕様群(JWSJWEJWKJWAJWT)は、当然 FAPI の仕様書を読む際にも前提知識となるので、完全に理解していなければならない。

3 年以上前に策定された PKCERFC 7636)は、現在では RFC 6749 と RFC 6750 に並ぶ OAuth 2.0 の基本仕様扱いされており、常識の範疇となっている。

以下に、FAPI 仕様書を読むに先立って最低限一度は目を通しておくべき仕様書を挙げる。

これらの仕様書を読むにあたり、助けになるであろう解説記事を挙げる。必要に応じて参照してほしい。

なお、仕様書は原文(英語)を読むに限る。仕様策定作業に参画すれば分かるが、母国語が英語の技術者の間でも原文の解釈に揺れが生じるくらいだから、日本語訳を参照することは、少なくとも実装者レベルではありえない。


0.2. Mutual TLS

一般的には、Mutual TLS というと、単に「TLS 通信時にクライアント側も証明書を提示する」ことを意味する。しかし、FAPI の文脈では、Mutual TLS は『OAuth 2.0 Mutual TLS Client Authentication and Certificate Bound Access Tokens』(以降 MTLS)(2019 年 1 月時点ではまだドラフト段階)という仕様書で定義されている次の二つをさす。


  1. クライアント証明書による OAuth クライアント認証

  2. クライアント証明書に紐付くトークンに関する処理


0.2.1. クライアント証明書による OAuth クライアント認証

Confidential クライアント(RFC 6749, 2. Client Types)は、トークンエンドポイント(RFC 6749, 3.2. Token Endpoint)にアクセスする際クライアント認証(RFC 6749, 2.3. Client Authentication)をおこなわなければならない。クライアント認証とは、当該クライアントアプリケーションが自身の秘密の認証情報を持っていることを証明する処理だ。

※:CIBA のバックチャネル認証エンドポイントなど、クライアント認証を必要とするエンドポイントは他にも存在する。

クライアント認証方式は幾つか存在し、OIDC Core の『9. Client Authentication』には次のものが挙げられている(none を除く)。

方式名
定義場所
説明

client_secret_basic
RFC 6749
クライアント ID とクライアントシークレットを用いた Basic 認証

client_secret_post
RFC 6749
クライアント ID とクライアントシークレットをリクエスト本文に埋め込む

client_secret_jwt
RFC 7523
クライアントシークレットを鍵とし、対称鍵系アルゴリズムで署名した JWT を渡す

private_key_jwt
RFC 7523
非対称鍵系アルゴリズムの秘密鍵で署名した JWT を渡す

client_secret_basicclient_secret_post では、秘密の認証情報であるクライアントシークレットの値を直接サーバーに提示することで、秘密の認証情報を持っていることを示し、もってクライアント認証とする。

client_secret_jwt では、クライアントシークレットで JWT に署名をしてそれをサーバーに提示することで、クライアントシークレットを持っていることを間接的に証明する。一方 private_key_jwt では、署名はクライアントが保持する非対称鍵アルゴリズムの秘密鍵でおこなわれ、サーバーは当該秘密鍵に対応する公開鍵でその署名を検証する。

MTLS の『2. Mutual TLS for OAuth Client Authentication』は、上記とは別に、新たに次の二つのクライアント認証方式を定義する。

方式名
説明

tls_client_auth
TLS 通信で用いられた PKI のクライアント証明書を用いる

self_signed_tls_client_auth
TLS 通信で用いられた自己署名クライアント証明書を用いる

tls_client_auth では、クライアント・サーバー間の TLS 通信で用いられたクライアント証明書がクライアント認証に使われる。サーバー側は当該クライアント証明書が有効であることを確認し(この処理は OAuth に関係なく TLS 通信であれば常に行われるべきこと)、その主体者識別子(Subject Distinguished Name)もしくは SAN(Subject Alternative Name)のエントリーのいずれかが事前に登録されている値と一致するかどうかを調べる。そのため、クライアントは、使う予定のクライアント証明書の主体者識別子もしくは SAN のエントリーのいずれかを事前にサーバーに登録しておかなければならない。同仕様書では、これらのデータを表すためのメタデータとして、新たに次のものが定義されている。


  • tls_client_auth_subject_dn

  • tls_client_auth_san_dns

  • tls_client_auth_san_uri

  • tls_client_auth_san_ip

  • tls_client_auth_san_email

self_signed_tls_client_auth では、PKI の証明書ではなく、自己署名証明書をクライアント証明書として用いる。このクライアント認証方式を用いるためには、クライアントは、当該自己署名証明書・公開鍵を事前にサーバーに登録しておかなければならない。


0.2.2. クライアント証明書に紐付くトークン

従来のアクセストークンは、漏洩してしまうと、攻撃者がそれを用いて API にアクセスすることができてしまう。ちょうど、電車の切符を失くしてしまったら、それを拾った他の人が電車に乗れてしまうのと同じことだ。

この脆弱性を軽減する手段として、アクセストークンの発行対象者とアクセストークンの利用者が同一であることを API アクセス時にチェックするという方法が考えられる。ちょうど、国際線航空チケットの利用時に、チケットと併せてパスポートの提示も要求し、正規のチケット利用者とチケット持参者が同一であることを確認する手続きと同じだ。

FAPI では、この仕組みのことを『holder of key mechanism』と総称しており、『Mutual TLS』と『Token Binding』の二つを挙げている。この文脈における Mutual TLS は、MTLS の『3. Mutual TLS Client Certificate Bound Access Tokens』で説明されている技術をさす。

Mutual TLS という呼称は多義性があり、実際に下記のやりとりを経験したので、


私:「御社の API 管理ソリューションは(holder of key mechanism としての)Mutual TLS をサポートしていませんよね?」

中の人:「いや、(TLS 通信時にクライアント証明書を要求することはできるので)Mutual TLS はサポートしていますよ。」


個人的には holder of key mechanism における Mutual TLS のことを『Certificate Binding』と呼ぶことにした。名称として Token Binding との対称性もあるし、また、実際の実装も「証明書とアクセストークンを紐づける」だけに落ち着くので、その証明書の出所が TLS 通信の中から抜き出したクライアント証明書なのか否かは、実装レベルでは関係ないからだ。

それはさておき、Mutual TLS、もとい、Certificate Binding の実装では、認可サーバーのトークンエンドポイントは、アクセストークン発行時、TLS 通信で提示されたクライアント証明書のハッシュ値を計算し、そのハッシュ値をアクセストークンと紐付けて覚えておく(もしくはアクセストークンの実装が JWT ならばその JWT の中にハッシュを埋め込む)。クライアントは、そのアクセストークンを使ってリソースサーバーの API にアクセスに行くが、その際、トークンエンドポイントとの通信で使ったものと同じクライアント証明書を使う。リソースサーバーの API の実装は、リクエストからアクセストークンとクライアント証明書を抜き出し、当該クライアント証明書のハッシュ値を計算して、その値が当該アクセストークンと紐付いているハッシュ値と同一であるかどうかを確認する。同一であれば API アクセスを許可し、そうでなければ API アクセスを拒否する。

Certificate Binding は、クライアント証明書にアクセスできさえすればいいので、比較的実現が容易な holder of key mechanism である。一方の Token Binding は、TLS レイヤーや HTTP レイヤーなど、各所に手を入れる必要があり、実装のハードルは高い。また、コミュニティーから強く再考を要望されていたにもかかわらず(「Intent to Remove: Token Binding」のメールスレッド)、Chrome が Token Binding 機能を削除したこともあり、雲行きも怪しい。しかしながら、とにもかくにも 2018 年 10 月初旬に関連仕様書群が RFC 化された。

RFC 番号
タイトル

RFC 8471
The Token Binding Protocol Version 1.0

RFC 8472
Transport Layer Security (TLS) Extension for Token Binding Protocol Negotiation

RFC 8473
Token Binding over HTTP

OAuth 2.0 Token Binding』(2019 年 1 月時点ではまだドラフト段階)は、これらの RFC 群を土台として OAuth 2.0 のトークン群に Token Binding を適用する方法を定める仕様である。


0.3. JARM

FAPI Implementer's Draft 第二版と同時期に承認された仕様が JARM(JWT Secured Authorization Response Mode for OAuth 2.0)だ。ドイツの金融業界の要望に対応するため、驚くほどのスピードで策定され、駆け込みで FAPI Implementer's Draft 第二版と一緒に処理された。

FAPI Part 2 で JARM が出てくるので、ここで簡単に紹介する。

この仕様により、認可リクエストの response_mode パラメーターの値として次のものを指定することが可能となる。


  • query.jwt

  • fragment.jwt

  • form_post.jwt

  • jwt

これらを指定すると、認可レスポンスのレスポンスパラメーター群が一つの JWT にまとめられresponse={JWT} という形式で返ってくる。

JARM については『OAuth 2.0 の認可レスポンスとリダイレクトに関する説明』内の『JWT Secured Authorization Response Mode』に、response_mode については『OAuth & OpenID Connect 関連仕様まとめ』の『13. 応答モード(response_mode)』に解説があるので、参照してほしい。


1. Part 1: Read-Only API Security Profile

前提知識の紹介が終わったので、本題の FAPI の解説に入る。まず、参照系 API のセキュリティープロファイルである Part 1 から。


1.1. Part 1: 認可サーバーに対する要求事項

Part 1 の『5.2.2. Authorization server』に、認可サーバーに対する要求事項が列挙されているので、一つ一つ見ていく。

Part 1: 5.2.2. Authorization server, 1.

shall support confidential clients;

Confidential クライアントをサポートしなければならない。

Part 1: 5.2.2. Authorization server, 2.

should support public clients;

Public クライアントをサポートすべきである。

Confidential クライアントと Public クライアントの定義は RFC 6749 の『2.1. Client Types』に書いてある。FAPI の仕様書を読むレベルの人にとっては前提知識なので、これらの違いをここでは説明しない。しかしながら、OAuth 2.0 のフローとクライアントタイプの関係は、誤解されることが大変多い。もし、「仕様上、フローとクライアントタイプの組み合わせのうち、明示的に禁止されているのは、クライアントクレデンシャルズフローと Public クライアントの組み合わせだけ」ということを認識していない場合は、『OAuth 2.0 のフローとクライアントタイプの関係』に一度目を通してほしい。この認識がないと、FAPI 仕様書を読み誤る。

Part 1: 5.2.2. Authorization server, 3.

shall provide a client secret that adheres to the requirements in section 16.19 of [OIDC] if a symmetric key is used;

共有鍵を用いる場合、OIDC Core 16.19 の要求事項を満たすクライアントシークレットを提供しなければならない。

署名処理や暗号化で対称鍵系アルゴリズムを用いる場合、OIDC Core では、クライアントシークレットを元に算出した値を共有鍵として用いることになっている。元となるクライアントシークレットのエントロピーが、アルゴリズムが要求するエントロピーよりも低いと、アルゴリズムの強度が損なわれてしまう。そこで、OIDC Core の『16.19 Symmetric Key Entropy』は、利用するアルゴリズムに対してクライアントシークレットが十分なエントロピーを持つことを要求している。例えば、ID トークンの署名アルゴリズムとして HS256(HMAC using SHA-256)を使用する場合、クライアントシークレットには最低限 256 ビットのエントロピーが求められる。関連する議論として『OAuth 2.0 + OpenID Connect のフルスクラッチ実装者が知見を語る』の『クライアントシークレット』も参照のこと。

Part 1: 5.2.2. Authorization server, 4.

shall authenticate the confidential client at the token endpoint using one of the following methods:


  1. Mutual TLS for OAuth Client Authentication as specified in section 2 of [MTLS];


  2. client_secret_jwt or private_key_jwt as specified in section 9 of [OIDC];

トークンエンドポイントでは Confidential クライアントを次のいずれかの方式で認証しなければならない。


  1. MTLS の『2. Mutual TLS for OAuth Client Authentication』

  2. OIDC Core の『9. Client Authentication』に挙げられている client_secret_jwt もしくは private_key_jwt

トークンエンドポイントにおけるクライアント認証方式として、RFC 6749 で定義されている client_secret_basicclient_secret_post を利用できないので注意が必要だ。

Part 1: 5.2.2. Authorization server, 5.

shall require a key of size 2048 bits or larger if RSA algorithms are used for the client authentication;

クライアント認証で RSA アルゴリズムを用いる場合、キーサイズは 2048 ビット以上

Part 1: 5.2.2. Authorization server, 6.

shall require a key of size 160 bits or larger if elliptic curve algorithms are used for the client authentication;

クライアント認証で楕円曲線アルゴリズムを用いる場合、キーサイズは 160 ビット以上

例えば、クライアント認証で private_key_jwt を用い、JWT の署名に RSA アルゴリズムを用いる場合、キーサイズが 2048 ビット以上でなければならない。同様に、楕円曲線アルゴリズムであれば 160 ビット以上のキーサイズが求められる。

Part 1: 5.2.2. Authorization server, 7.

shall require [RFC7636] with S256 as the code challenge method;

RFC 7636 て定義されるリクエストパラメーター群が必要。Code challenge method は S256

認可コード横取り攻撃への対抗策である RFC 7636 の実装が要求される。

RFC 7636 により、認可リクエストに code_challengecode_challenge_method というリクエストパラメーター群、トークンリクエストに code_verifier というリクエストパラメーターが追加される。code_challenge_method リクエストパラメーターが省略されたときのデフォルト値は plain なので、S256 が要求されているということは、認可リクエストは明示的に code_challenge_method=S256 というリクエストパラメーターを含まなければならないということだ。

RFC 7636 については『PKCE: 認可コード横取り攻撃対策のために OAuth サーバーとクライアントが実装すべきこと』を参照してほしい。

Part 1: 5.2.2. Authorization server, 8.

shall require redirect URIs to be pre-registered;

リダイレクト URI は事前登録が必要

RFC 6749 では、ある条件下ではリダイレクト URI の登録を省略できる。しかし、FAPI ではリダイレクト URI は必ず事前登録しておかなければならない。

Part 1: 5.2.2. Authorization server, 9.

shall require the redirect_uri parameter in the authorization request;

認可リクエストには redirect_uri パラメーターが必要

RFC 6749 では、ある条件下では認可リクエストの redirect_uri パラメーターを省略することができる。しかし、FAPI では redirect_uri パラメーターは常に必要だ。なお、OIDC Core でも redirect_uri パラメーターは常に必要だ。

Part 1: 5.2.2. Authorization server, 10.

shall require the value of redirect_uri to exactly match one of the pre-registered redirect URIs;

redirect_uri の値は事前登録されたものと完全一致しなければならない。

RFC 6749 では、redirect_uri パラメーターで指定されたリダイレクト URI が登録されているリダイレクト URI と合致するかの判定方法は、(登録されているリダイレクト URI が完全 URI でない限り)RFC 3986(Uniform Resource Identifier (URI): Generic Syntax)の『6. Normalization and Comparison』に記載されている方法を用いることになっている。一方、FAPI では、単純文字列比較による完全一致が求められる。なお、OIDC Core も完全一致を要求する。

Part 1: 5.2.2. Authorization server, 11.

shall require user authentication at LoA 2 as defined in [X.1254] or more;

ユーザー認証は X.1254 で定義される LoA 2 以上でなければならない。

認可処理時に実行されるユーザー認証処理が、X.1254(Entity authentication assurance framework)で定義されている LoA(Level of assurance)の 2 以上を満たすことが求められている。下記は X.1254 の『6.2 Level of assurance 2 (LoA2)』に記載されている LoA 2 の定義である。


At LoA2, there is some confidence in the claimed or asserted identity of the entity. This LoA is used when moderate risk is associated with erroneous authentication. Single-factor authentication is acceptable. Successful authentication shall be dependent upon the entity proving, through a secure authentication protocol, that the entity has control of the credential. Controls should be in place to reduce the effectiveness of eavesdroppers and online guessing attacks. Controls shall be in place to protect against attacks on stored credentials.

For example, a service provider might operate a website that enables its customers to change their address of record. The transaction in which a beneficiary changes an address of record may be considered an LoA2 authentication transaction, as the transaction may involve a moderate risk of inconvenience. Since official notices regarding payment amounts, account status, and records of changes are usually sent to the beneficiary's address of record, the transaction additionally entails moderate risk of unauthorized release of PII. As a result, the service provider should obtain at least some authentication assurance before allowing this transaction to take place.


Part 1: 5.2.2. Authorization server, 12.

shall require explicit consent by the user to authorize the requested scope if it has not been previously authorized;

過去に認可を得ていないスコープについては、ユーザーの同意を明示的に得なければならない。

それはそうだろう。

Part 1: 5.2.2. Authorization server, 13.

should verify that the authorization code (section 1.3.1 of [RFC6749]) has not been previously used;

認可コードが過去に使われていないことを検証すべきである。

認可コードの再利用を不可とすることと、過去に利用されたかどうかを検証することは、同一ではない。もしも検証が仕様書で必須となっていたなら(should ではなく shall となっていたなら)、現在の実装が「認可コードを十分にランダムに生成し、それが利用されたタイミングでデータベースから削除する」となっている場合、過去に利用されたかどうかを検証するためには、使用後も削除せずに検証のためだけに永遠に覚えておかなければならない。認可コードが十分にランダムに生成できているのであれば、これは無駄である。「世の中のほとんどの実装は、認可コード使用後、データベースから当該認可コードを削除することにより再利用を防いでいるから、認可コードが過去に使われたかどうかの検証なんてしていない(それでかまわない)」と、某米国在住の世界的ソフトウェアエンジニアが発言している。

Part 1: 5.2.2. Authorization server, 14.

shall return token responses that conform to section 4.1.4 of [RFC6749];

RFC 6749 の 4.1.4 に準拠するトークンレスポンスを返さなければならない。

これは、わざわざ FAPI 仕様書で言及することでもない。

Part 1: 5.2.2. Authorization server, 15.

shall return the list of granted scopes with the issued access token;

付与されたスコープのリストを発行されたアクセストークンと共に返さなければならない。

RFC 6749 では、認可サーバーがクライアントアプリケーションにアクセストークンを発行する際、そのアクセストークンに紐付けられたスコープ群のリストをアクセストークンと共にクライアントに返すかどうかは、クライアントが元々要求したスコープ群と結果として付与されたスコープ群が異なる場合を除き、任意である(RFC 6749, 5.1. Successful Response)。しかし、FAPI では、付与されたスコープ群のリストは常に応答に含まれる。

Part 1: 5.2.2. Authorization server, 16.

shall provide opaque non-guessable access tokens with a minimum of 128 bits of entropy where the probability of an attacker guessing the generated token is less than or equal to 2^(-160) as per [RFC6749] section 10.10;

アクセストークンのエントロピーは 128 ビット以上

発行するアクセストークンのエントロピーが 128 ビット以上であることが要求される。例えば 128 ビットの値を base64url でエンコーディングすると 22 文字になるため、もしも手元の認可サーバーが、英数字のみで構成されるアクセストークンを発行し、その長さが 22 文字未満なのであれば、この要件を満たしていないことは明らかなので、実装変更が必要となる。

Part 1: 5.2.2. Authorization server, 17.

should clearly identify long-term grants to the user during authorization as in 16.18 of [OIDC]; and

付与する権限が長期間有効になる場合、認可処理中にその旨明示すべきである。

例えば、権限付与の影響が長期に渡る場合、「銀行口座の取引情報へのアクセスを許可しようとしています」という説明だけでは不十分で、「このアクセス許可は今後三ヶ月間有効です」という説明を付け加えるべき、という要求事項である。

Part 1: 5.2.2. Authorization server, 18.

should provide a mechanism for the end-user to revoke access tokens and refresh tokens granted to a client as in 16.18 of [OIDC].

クライアントに与えたアクセストークンとリフレッシュトークンをユーザーが取り消しできる仕組みを提供すべきである。

アクセストークンの実装が JWT の場合、一度発行したアクセストークンを取り消すことはできない。そのため、アクセストークンの有効期限を短くすることが必須で、その上で「(それでも)有効期限中は取り消しできないが、運用上問題無い」という妥協が求められる。加えて、アクセストークンの属性を後から変更することができない、発行済みアクセストークンのリストを取得できない、アクセストークンに関する情報は全てクライアント側に渡る、などのデメリットも受け入れなければならない。しかしながら、これらは JWT のメリットとのトレードオフであり、一概に悪いとは言えない。実際、アクセストークンの実装を JWT としている認可サーバーの実装は多く存在する。

ちなみに、「発行済みアクセストークンを即座に取り消しできないことは汎用ソリューションとしては致命傷になりかねない」との判断もあり、Authlete が発行するアクセストークンの実装は JWT ではない。

Part 1: 5.2.2. Authorization server, 19.

shall return an invalid_client error as defined in 5.2 of [RFC6749] when mis-matched client identifiers were provided through the client authentication methods that permits sending the client identifier in more than one way;

クライアント識別子の指定方法を複数持つクライアント認証方式において、クライアント識別子が複数含まれ、それらが一致しない場合、invalid_client エラーを返さなければならない。

FAPI Part 1 では、クライアント認証は MTLS もしくは JWT 系(client_secret_jwtprivate_key_jwt)とされている。

MTLS の場合、クライアント認証にクライアント証明書が用いられるが、その証明書にはクライアント識別子は含まれていない。そのため、別途明示的に client_id リクエストパラメーターを用いてクライアント識別子を指定しなければならない。

一方の JWT 系のクライアント認証では、client_assertion リクエストパラメーターで指定された JWT の iss クレームの値がクライアント識別子を表しているので、client_id リクエストパラメーターは不要である。なお、RFC 7523, 3. および OIDC Core, 9. によれば、クライアント認証に JWT を使う場合は sub クレームもクライアント識別子をあらわす。

MTLS の場合はクライアント識別子を表すのは client_id リクエストパラメーターだけである。一方の JWT 系クライアント認証では iss クレームと sub クレームの両方がクライアント識別子を表す。これら二つのクレーム群が一致しないといけないのはもちろんのこと、仮に、冗長ではあるが client_id リクエストパラメーターも指定されていた場合、その値も一致しなければならない。

Part 1: 5.2.2. Authorization server, 20.

shall require redirect URIs to use the https scheme;

リダイレクト URI のスキームは https でなければならない。

FAPI Implementer's Draft 第二版でさらっとこの一文が追加されたが、影響は大きい。この文により、FAPI ではリダイレクト URI にカスタムスキームを使えないこととなった。よって、外部 Web サーバーを立てずにクライアント側だけでリダイレクト処理を完結させたい場合、BCP 212(OAuth 2.0 for Native Apps)の『7.2. Claimed "https" Scheme URI Redirection』で言及されている手法を使う必要がある。


1.1.2. ユーザー識別子を返す場合

5.2.2.1. Returning authenticated user's identifier Authorization server』には、次の条件:


"Further, if it is desired to provide the authenticated user's identifier to the client in the token response, the authorization server:",


が当てはまる場合に認可サーバーが追加で従わなければならない要求事項が列挙されている。"if it is desired to provide the authenticated user's identifier" という条件は、直訳は「認証されたユーザーの識別子の提供を要求されている場合」であるが、それが技術的に意味するところは「ID トークンの発行を要求されている場合」である。

Part 1: 5.2.2.1. Returning authenticated user's identifier Authorization server, 1.

shall support the authentication request as in Section 3.1.2.1 of [OIDC];

OIDC Core の 3.1.2.1 の認証リクエストをサポートしなければならない。

OIDC Core の『3.1.2.1. Authentication Request』は、OpenID Connect における認可エンドポイントへのリクエストの定義だ。RFC 6749 では認可エンドポイントへのリクエストを『認可リクエスト』と呼び、OIDC Core では『認証リクエスト』と呼ぶが、呼称はさておき、認可エンドポイントの動作仕様定義が OIDC Core の中心であることを考えると、この規定は、「OIDC Core をサポートすること」とざっくり言っているに等しい。

Part 1: 5.2.2.1. Returning authenticated user's identifier Authorization server, 2.

shall perform the authentication request verification as in Section 3.1.2.2 of [OIDC];

OIDC Core の 3.1.2.2 に従って認証リクエストを検証しなければならない。

Part 1: 5.2.2.1. Returning authenticated user's identifier Authorization server, 3.

shall authenticate the user as in Section 3.1.2.2 and 3.1.2.3 of [OIDC];

OIDC Core の 3.1.2.2 と 3.1.2.3 に従ってユーザーを認証しなければならない。

Part 1: 5.2.2.1. Returning authenticated user's identifier Authorization server, 4.

shall provide the authentication response as in Section 3.1.2.4 and 3.1.2.5 of [OIDC] depending on the outcome of the authentication;

認証処理による生成物に応じて、OIDC Core の 3.1.2.4 と 3.1.2.5 に従って認証レスポンスを提供しなければならない。

Part 1: 5.2.2.1. Returning authenticated user's identifier Authorization server, 5.

shall perform the token request verification as in Section 3.1.3.2 of [OIDC]; and

OIDC Core の 3.1.3.2 に従ってトークンリクエストの検証をおこなわなければならない。

Part 1: 5.2.2.1. Returning authenticated user's identifier Authorization server, 6.

shall issue an ID Token in the token response when openid was included in the requested scope as in Section 3.1.3.3 of [OIDC] with its sub value corresponding to the authenticated user and optional acr value in ID Token.

要求された scopeopenid が含まれていた場合、認証されたユーザーを示す sub クレームと、オプショナルで acr クレームを含む ID トークン発行し、トークンレスポンスに含めなければならない。

上記全て、簡単に言うと、「OIDC Core の仕様に従ってください」と言っているに過ぎない。


1.2. Part 1: Public クライアントに対する要求事項

Part 1 の『5.2.3. Public client』に、Public クライアントに対する要求事項が列挙されているので、一つ一つ見ていく。

Part 1: 5.2.3. Public client, 1.

shall support [RFC7636] or the mechanisms defined in Financial-grade API - Part 2;

RFC 7636 もしくは FAPI Part 2 で定義されている仕組みをサポートしなければならない。

RFC 7636 は PKCE のことだが、「FAPI Part 2 で定義されている仕組み」とは何をさすのか? 仕様書の字面だけでは不明瞭である。認可コードに対する追加要求については Part 2 で言及があるが、議論の余地がある。後述の Part 2, 5.2.2., 5 に関する議論を参照のこと。

Part 1: 5.2.3. Public client, 2.

shall use S256 as the code challenge method for the [RFC7636];

Code challenge method に S256 を用いなければならない。

認可リクエストに code_challenge_method=S256 を含めなさいということ。

Part 1: 5.2.3. Public client, 3.

shall use separate and distinct redirect URI for each authorization server that it talks to;

認可サーバー毎に別々のリダイレクト URI を用いなければならない。

Part 1: 5.2.3. Public client, 4.

shall store the redirect URI value in the resource owner's user-agents (such as browser) session and compare it with the redirect URI that the authorization response was received at, where, if the URIs do not match, the client shall terminate the process with error;

リダイレクト URI の値をセッションに保存しておき、認可レスポンスを受信したリダイレクト URI と比較すること。URI が一致しない場合、クライアントは処理をエラーとして終了しなければならない。

Part 1: 5.2.3. Public client, 5.

shall adhere to the best practice stated by [BCP212]; and

BCP 212(OAuth 2.0 for Native Apps)で述べられているベストプラクティスに従わなければならない。

これらは書いてある通り。

Part 1: 5.2.3. Public client, 6.

shall implement an effective CSRF protection.

CSRF 対策を実装すること。

通常、CSRF 対策はサーバー側で実装するものだが、Public クライアントの要求事項としての CSRF 対策とは何をさすのか? これは、リダイレクト URI のための CSRF 対策のことである。下記は、RFC 6749 の『10.12. Cross-Site Request Forgery』からの抜粋である。


The client MUST implement CSRF protection for its redirection URI. This is typically accomplished by requiring any request sent to the redirection URI endpoint to include a value that binds the request to the user-agent's authenticated state (e.g., a hash of the session cookie used to authenticate the user-agent). The client SHOULD utilize the "state" request parameter to deliver this value to the authorization server when making an authorization request.


ここまでの 1. 〜 6. に加え、" if it is desired to obtain a persistent identifier of the authenticated user" であれば(認証されたユーザーの永続識別子が要求されていれば)、つまりは ID トークンが要求されていれば、

Part 1: 5.2.3. Public client, 7.

shall include openid in the scope value; and

scopeopenid を含まなければならない。

Part 1: 5.2.3. Public client, 8.

shall include nonce parameter defined in Section 3.1.2.1 of [OIDC] in the authentication request.

nonce パラメーターを含まなければならない。

一方で、"If openid is not in the scope value" であれば(scopeopenid を含めないケースでは)、

Part 1: 5.2.3. Public client, 9.

shall include the state parameter defined in section 4.1.1 of [RFC6749].

state パラメーターを含まなければならない。


1.3. Part 1: Confidential クライアントに対する要求事項

Part 1 の『5.2.4. Confidential client』に、Confidential クライアントに対する要求事項が列挙されている。Confidential クライアントに対する要求事項は、「Public クライアントに対する要求事項に加えて」という位置付けなので、Confidential クライアントは、5.2.4. に挙げられている項目だけでなく、5.2.3. に挙げられている項目にも対応する必要がある。

Part 1: 5.2.4. Confidential client, 1.

shall support the following methods to authenticate against the token endpoint:


  1. Mutual TLS for OAuth Client Authentication as specified in section 2 of [MTLS];


  2. client_secret_jwt or private_key_jwt as specified in section 9 of [OIDC];

トークンエンドポイントにおけるクライアント認証方式として次のものをサポートしなければならない。


  1. MTLS の『2. Mutual TLS for OAuth Client Authentication』

  2. OIDC Core の『9. Client Authentication』に挙げられている client_secret_jwt もしくは private_key_jwt

RFC 6749 で定義されているクライアント認証方式(client_secret_basicclient_secret_post)は使えないので注意。

Part 1: 5.2.4. Confidential client, 2.

shall use RSA keys with a minimum 2048 bits if using RSA cryptography;

RSA 暗号を用いる場合は 2048 ビット以上の鍵を使わなければならない。

Part 1: 5.2.4. Confidential client, 3.

shall use elliptic curve keys with a minimum of 160 bits if using Elliptic Curve cryptography; and

楕円曲線暗号を用いる場合は 160 ビット以上の鍵を使わなければならない。

Part 1: 5.2.4. Confidential client, 4.

shall verify that its client secret has a minimum of 128 bits if using symmetric key cryptography.

対称鍵系暗号を用いる場合はクライアントシークレットが 128 ビット以上であることを検証しなければならない。

これらは、暗号化された JWT を扱う場合に関係してくる。


1.4. Part 1: 参照系 API に対する要求事項

Part 1 の『6.2.1. Protected resources provisions』に、参照系 API に対する要求事項が列挙されているので、一つ一つ見ていく。

Part 1: 6.2.1. Protected resources provisions, 1.

shall support the use of the HTTP GET method as in Section 4.3.1 of [RFC7231];

HTTP GET メソッドをサポートしなければならない。

Part 1: 6.2.1. Protected resources provisions, 2.

shall accept access tokens in the HTTP header as in Section 2.1 of OAuth 2.0 Bearer Token Usage [RFC6750];

RFC 6750 の 2.1. で定義されている方法でアクセストークンを受け取れなければならない。

つまり、Authorization: Bearer アクセストークン という形式の Authorization HTTP ヘッダーによりアクセストークンを受け取れなければならない。

Part 1: 6.2.1. Protected resources provisions, 3.

shall not accept access tokens in the query parameters stated in Section 2.3 of OAuth 2.0 Bearer Token Usage [RFC6750];

RFC 6750 の 2.3. で定義されている方法でアクセストークンを受け取ってはならない。

つまり、access_token=アクセストークン という形式のクエリーパラメーターでアクセストークンを受け取ってはならない

Part 1: 6.2.1. Protected resources provisions, 4.

shall verify that the access token is neither expired nor revoked;

アクセストークンが有効期限切れでないこと、取り消しされていないことを検証しなければならない。

Part 1: 6.2.1. Protected resources provisions, 5.

shall verify that the scope associated with the access token authorizes the reading of the resource it is representing;

アクセストークンに紐づくスコープが当該リソースの読み取りを許可していることを検証しなければならない。

Part 1: 6.2.1. Protected resources provisions, 6.

shall identify the associated entity to the access token;

アクセストークンに紐づくエンティティーを特定しなければならない。

Part 1: 6.2.1. Protected resources provisions, 7.

shall only return the resource identified by the combination of the entity implicit in the access and the granted scope and otherwise return errors as in section 3.1 of [RFC6750];

アクセストークンに紐づくエンティティーと付与されたスコープの組みにより特定されるリソースのみを返さなければならない。できなければ RFC 6750 の 3.1. 内のエラーを返さなければならない。

RFC 6750 の『3.1. Error Codes』には invalid_requestinvalid_tokeninsufficient_scope の三つのエラーコードが定義されている。ただ、エラーコードを埋め込む場所はレスポンスボディーではなく WWW-Authenticate HTTP ヘッダーであることに注意。

Part 1: 6.2.1. Protected resources provisions, 8.

shall encode the response in UTF-8 if applicable;

レスポンスは UTF-8 でエンコードする。

Part 1: 6.2.1. Protected resources provisions, 9.

shall send the Content-type HTTP header Content-Type: application/json; charset=UTF-8 if applicable;

応答は JSON とし、Content-Type HTTP ヘッダーを適切に含める。

Part 1: 6.2.1. Protected resources provisions, 10.

shall send the server date in HTTP Date header as in section 7.1.1.2 of [RFC7231];

サーバー時刻を示す Date HTTP ヘッダーを含める。

Part 1: 6.2.1. Protected resources provisions, 11.

shall set the response header x-fapi-interaction-id to the value received from the corresponding fapi client request header or to a [RFC4122] UUID value if the request header was not provided to track the interaction, e.g., x-fapi-interaction-id: c770aef3-6784-41f7-8e0e-ff5f97bddb3a; and

x-fapi-interaction-id HTTP ヘッダーを応答に含める。その値は、リクエストに x-fapi-interaction-id が含まれていればそれと同じ値を、含まれていなければ UUID を生成してセットする。

これは FAPI 特有の要求事項だ。FAPI に対応する API は、x-fapi-interaction-id HTTP ヘッダーをレスポンスに含めなければならない。

Part 1: 6.2.1. Protected resources provisions, 12.

shall log the value of x-fapi-interaction-id in the log entry.

x-fapi-interaction-id の値をログに残さなければならない。

これも FAPI 特有の要求事項。API のリクエスト・レスポンス仕様には何ら影響を及ぼさない要求事項だが、クライアント側のログとサーバー側のログの付き合わせを容易にするための仕組みとして用いられる。

Part 1: 6.2.1. Protected resources provisions, 13.

should support the use of Cross Origin Resource Sharing (CORS) [CORS] and or other methods as appropriate to enable JavaScript clients to access the endpoint if it decides to provide access to JavaScript clients.

JavaScript クライアントからのアクセスを許容する場合は Cross Origin Resource Sharing をサポートすべき。


1.5. Part 1: 参照系 API アクセス時のクライアントに対する要求事項

Part 1 の『6.2.2. Client provisions』に、参照系 API アクセス時のクライアントに対する要求事項が列挙されているので、一つ一つ見ていく。

Part 1: 6.2.2. Client provisions, 1.

shall send access tokens in the HTTP header as in Section 2.1 of OAuth 2.0 Bearer Token Usage [RFC6750]; and

RFC 6750 の 2.1 で定義されている方法でアクセストークンを送らなければならない。

つまり、Authorization: Bearer アクセストークン という形式でアクセつトークンを API に提示する。

Part 1: 6.2.2. Client provisions, 2.

(withdrawn);

(撤回)

Part 1: 6.2.2. Client provisions, 3.

may send the last time the customer logged into the client in the x-fapi-auth-date header where the value is supplied as a HTTP-date as in section 7.1.1.1 of [RFC7231], e.g., x-fapi-auth-date: Tue, 11 Sep 2012 19:43:31 GMT; and

ユーザーが最後にログインした時刻を、HTTP-date 形式で x-fapi-auth-date ヘッダーに含めて送信してもよい。

Part 1: 6.2.2. Client provisions, 4.

may send the customer’s IP address if this data is available in the x-fapi-customer-ip-address header, e.g., x-fapi-customer-ip-address: 198.51.100.119; and

ユーザーの IP アドレスを x-fapi-customer-ip-address ヘッダーに含めて送信してもよい。

Part 1: 6.2.2. Client provisions, 5.

may send the x-fapi-interaction-id request header whose value is a [RFC4122] UUID to the server to help correlate log entries between client and server, e.g., x-fapi-interaction-id: c770aef3-6784-41f7-8e0e-ff5f97bddb3a.

クライアント側のログとサーバー側のログの付き合わせを容易にするため、UUID を x-fapi-interaction-id ヘッダーに含めて送信してもよい。

3 〜 5 は、FAPI 固有の x-fapi-* HTTP ヘッダーに関する項目となっていて、送信するかどうかはクライアントの自由だ。まとめると下記の通り。

HTTP ヘッダー
内容

3
x-fapi-auth-date
ユーザーの最終ログイン時刻

4
x-fapi-customer-ip-address
ユーザーの IP アドレス

5
x-fapi-interaction-id
通信を識別するための UUID


1.6. Part 1: セキュリティー上の考慮事項

Part 1 の『7. Security considerations』に、セキュリティー上の考慮事項が列挙されている。要約すると以下の通り。

要約

7.1.

BCP 195 に従う。TLS 1.2 以降を使う。RFC 6125 に従う。

7.2.
Part 1 では認可リクエスト・レスポンスの認証は必須ではない。

7.3.
Part 1 では認可リクエスト改竄への対策は必須ではない。

7.4.1.
Part 1 では認可リクエストの暗号化に関する言及はない。

7.4.2.
トークンエンドポイントにおけるログから情報漏洩しないように注意。

7.4.3.
API において、リファラー経由で情報が漏れないように注意。アクセストークンの有効期限は短く。

7.5.
ネイティブアプリのリダイレクト URI のスキームも https

7.6.
FAPI 実装および下層の OAuth/OIDC 実装の両方とも完全で正確であることが重要。OpenID Certification を参照のこと。

FAPI Part 2 は、リクエストオブジェクトや Deteched Signature(後述)としての ID トークンの使用を必須とするなどして、Part 1 で挙げられているセキュリティー上の考慮事項に対する解決策を示している。セキュリティーリスクに対するより強固な対策が必要な際に Part 1 よりも Part 2 が推奨されるのはこれが理由だ。


2. Part 2: Read and Write API Security Profile

次は、更新系 API 用のセキュリティープロファイルである Part 2 を見ていく。


2.1. Detached Signature

Part 2 の『5.1. Introduction』では、『ID トークン』を『Detached Signature』として用いることが述べられている。

ID トークンは認可サーバーによって署名されるので、その内容を攻撃者が改竄しても、その改竄を検出することができる。ID トークンを受け取ったクライアントは、署名を検証することで、認可サーバーから送られてきたデータが手元に届くまでの間に改竄されていないことを確認できるのだ。

この機能を流用し、ID トークンの外部に置かれるレスポンスパラメーター群(例えば codestate)のハッシュ値を ID トークンの中に埋め込んでおけば、レスポンスを受け取ったクライアントは、「ID トークンの外部に置かれているレスポンスパラメーターの値のハッシュ値」を計算し、それが「ID トークンに埋め込まれているハッシュ値」と一致することを確認することで、当該リクエストパラメーターの値が途中で改竄されていないことを確認できる。

認可コードを表す code レスポンスパラメーターについては、そのハッシュ値を表す c_hash というクレームが、実は既に OIDC Core で定義済みである。同様に、アクセストークンを表す access_token レスポンスパラメーターについても、at_hash クレームが定義済みである。

まだ定義されていないのは state レスポンスパラメーターに対応するハッシュ値のためのクレームということで、『5.1. Introduction』では s_hash クレームが新たに定義されている。


s_hash

State hash value. Its value is the base64url encoding of the left-most half of the hash of the octets of the ASCII representation of the state value, where the hash algorithm used is the hash algorithm used in the alg header parameter of the ID Token's JOSE header. For instance, if the alg is HS512, hash the state value with SHA-512, then take the left-most 256 bits and base64url encode them. The s_hash value is a case sensitive string.


Part 2 では ID トークンを Detached Signature として使うため、本来の用途としての ID トークンが不要であったとしても、ID トークンを要求するリクエストを投げなければならない。具体的には、response_type リクエストパラメーターに id_token を含めなければならない。『5.2.2. Authorization Server』の 2 番目の項目で "shall require the response_type values code id_token or code id_token token;"response_typecode id_token または code id_token_token でなければならない)と要求しているのはそのためだ。

しかしながら、Implementer's Draft 第二版で追加された『5.2.5. JWT Secured Authorization Response Mode』により、JARM が使われた場合は Detached Signature として ID トークンを使う必要がなくなった。なぜなら、JARM により、レスポンスパラメーター群が全て一つの JWT にまとめられるからだ。これについては、後ほど再度触れる。


2.2. Part 2: 認可サーバーに対する要求事項

Part 2 の『5.2.2. Authorization server』に、認可サーバーに対する要求事項が列挙されているので、一つ一つ見ていく。

Part 2: 5.2.2. Authorization server, 1.

shall require the request or request_uri parameter to be passed as a JWS signed JWT as in clause 6 of [OIDC];

request または request_uri パラメーターが必要。

requestrequest_uri は OIDC Core の『6. Passing Request Parameters as JWTs』で定義されているパラメーターだ。これらを使うときは、まず、リクエストパラメーター群を一つの JWT にまとめる。この JWT をリクエストオブジェクトと呼ぶ。そして、そのリクエストオブジェクトを request リクエストパラメーターの値として直接指定するか、もしくは、そのリクエストオブジェクトが置かれている場所を示す URI を request_uri リクエストパラメーターの値として指定する。

OIDC Core ではリクエストオブジェクトへの署名は必須ではない。一方、FAPI Part 2 ではリクエストオブジェクトに署名が必要とされている。リクエストオブジェクトに署名がついていれば、認可サーバーはその署名を検証することで、クライアントから送られてきたリクエストパラメーター群が手元に届くまでの間に改竄されていないことを確認できる。

しかしながら、FAPI の仕様書を読んだときに一番驚いたのがこの規定だ。なぜなら、リクエストオブジェクトをサポートするための認可サーバー側の実装が、経験上かなり大変なことを知っていたからだ(参考→『リクエストオブジェクト処理手順』)。実装が大変なことと、OIDC Core でオプショナル機能扱いされていることもあり、OpenID Connect 対応を謳いながらリクエストオブジェクトをサポートしていない認可サーバーの実装は多い。FAPI Part 2 に対応するためには、リクエストオブジェクトをサポートする認可サーバーの実装を使わなければならないので注意が必要だ。

Part 2: 5.2.2. Authorization server, 2.

shall require the response_type values code id_token or code id_token token;

response_type パラメーターの値は code id_token もしくは code id_token token でなければならない。

ID トークンを Detached Signature として用いるため、本来の用途のために ID トークンを必要としていなくても、ID トークンの発行を要求するために id_tokenresponse_type パラメーターに含めなければならない。

しかし、先に述べたように、JARM が使われる場合、response_type パラメーターに id_token を含めなくてもよい。「JARM が使われる場合」とは、具体的には、response_mode パラメーターが認可リクエストに含まれ、その値が、query.jwtfragment.jwtform_post.jwtjwt のいずれかである場合をさす。

Part 2: 5.2.2. Authorization server, 3.

shall return ID Token as a detached signature to the authorization response;

Detached Signature として ID トークンを発行しなければならない。

ID トークンを発行しなければならないと書かれているが、前段の 2 で response_typeid_token を含めることが要求されており、その結果必然的に ID トークンが発行されるので、本規程はなくてもかまわない。なお、2 と同様、JARM が使われる場合、要求されていなければ ID トークンの発行は不要である。

Part 2: 5.2.2. Authorization server, 4.

shall include state hash, s_hash, in the ID Token to protect the state value if the client supplied a value for state. s_hash may be omitted from the ID Token returned from the Token Endpoint when s_hash is present in the ID Token returned from the Authorization Endpoint;

ID トークンに s_hash を含めなければならない。ただし、認可エンドポイントから発行された ID トークンに s_hash が含まれていれば、トークンエンドポイントから発行される ID トークンの s_hash は省略可能。

この規程も、JARM が使われる場合は従わなくてもよい。

Part 2: 5.2.2. Authorization server, 5.

shall only issue authorization code, access token, and refresh token that are holder of key bound;

HoK 対応の認可コード、アクセストークン、リフレッシュトークンのみを発行すること。

この文だが、実は問題がある。

HoK の方法は MTLS と Token Binding のどちらかとされているのだが(すぐ下の 6 の規程)、(トークンエンドポイントから発行される)アクセストークンとリフレッシュトークンはよいとしても、(認可エンドポイントから発行される)認可コードが問題になるのだ。

認可コードの HoK として MTLS を使うとしよう。このためには、認可エンドポイントとの間の通信が Mutual TLS である必要がある。認可エンドポイントと相対するのは、クライアントではなくて Web ブラウザなので、必然的な帰結として、Web ブラウザと認可エンドポイントとの間の通信が Mutual TLS である必要がある。ということは、あらかじめ、クライアント証明書を Web ブラウザにインストールしておき、Web ブラウザが認可エンドポイントと通信するときにそのクライアント証明書を Web ブラウザに使わせるようにしなければならない。

Part 2, 8.3.2. にも次のように書かれており、


When the FAPI client uses [MTLS] or [OAUTB], the authorization code is bound to the TLS channel, any phished client credentials and authorization codes submitted to the token endpoint cannot be used since the authorization code is bound to a particular TLS channel.


つまり、「認可コードは特定の TLS チャネルに結びついているため」と書かれているため、このように解釈せざるをえないのだ。

オーストラリアの Consumer Data Right Information Security Profile

(https://github.com/ConsumerDataStandardsAustralia/infosec) を議論している人の中にも、私と同じ解釈をした人がいた。

ただ、この解釈に従うと、「クライアント証明書を Web ブラウザにインストールして、認可エンドポイントとの Mutual TLS 通信で Web ブラウザにその証明書を使わせ、一方でまた、クライアントアプリケーションは同じ証明書をトークンエンドポイントとの通信に使わなければならない」。この Issue 内では、「それは非現実的だ」という結論に至っている。

一方、この規程を書いた当の FAPI ワーキンググループのほうなのだが、こちらでも、「そういうつもりではなかった」という論調になっている。



  • fapi Issue 202: authorization code and refresh token must be holder of key bound

FAPI Part 2, 5.2.2., 5. の規程には問題があると皆思っているので、この文はいつかは修正されることになる。

ただ、皆がやりたいことは既に分かっている。「盗まれたトークンさえあれば API に不正アクセスできる」という問題への対策を組み込みたいのだ。認可コードはさておき、アクセストークンについては HoK 対応可能なわけだから、FAPI 対応を謳う認可サーバーは、少なくともアクセストークンの HoK 対応は実装すべきである。

Part 2: 5.2.2. Authorization server, 6.

shall support [OAUTB] or [MTLS] as a holder of key mechanism;

holder of key mechanism として Token Binding もしくは MTLS をサポートすること。

アクセストークンとリフレッシュトークンについては Token Binding もしくは MTLS 対応が可能だが、認可コードについては上記の 5. の議論がある。「『認可コードについては PKCE を HoK として使う』と言ってしまえば話が楽になるのではないか」というコメントを fapi Issue 202 に書いてみたが、今後この議論はどう進むか確定的なことは言えない。

Part 2: 5.2.2. Authorization server, 7.

shall support user authentication at LoA 3 or greater as defined in [X.1254];

ユーザー認証は X.1254 で定義される LoA 3 以上でなければならない。

FAPI Part 1 で求められるユーザー認証の LoA は 2 以上だが、FAPI Part 2 では 3 以上となっている。下記は X.1254 の『6.3 Level of assurance 3 (LoA3)』に記載されている LoA 3 の定義である。


At LoA3, there is high confidence in the claimed or asserted identity of the entity. This LoA is used where substantial risk is associated with erroneous authentication. This LoA shall employ multifactor authentication. Any secret information exchanged in authentication protocols shall be cryptographically protected in transit and at rest (although LoA3 does not require the use of a cryptographic-based challenge-response protocol). There are no requirements concerning the generation or storage of credentials; they may be stored or generated in general purpose computers or in special purpose hardware.

For example, a transaction in which a company submits certain confidential information electronically to a government agency may require an LoA3 authentication transaction. Improper disclosure could result in a substantial risk for financial loss. Other LoA3 transaction examples include online access to accounts that allow the entity to perform certain financial transactions, or use by a third party contractor of a remote system to access potentially sensitive client personal information.


Part 2: 5.2.2. Authorization server, 8.

shall support signed ID Tokens;

署名付き ID トークンをサポートしなければならない。

OIDC Core の『2. ID Token』に "ID Tokens MUST be signed" と書かれており、ID トークンである時点で署名付きであることは確定しているので、この文はなくてもかまわない。

Part 2: 5.2.2. Authorization server, 9.

should support signed and encrypted ID Token;

ID トークンの署名と暗号化をサポートすべきである。

ID トークンの暗号化は OIDC Core でも言及されている。この文は shall ではなく should なので、暗号化をサポートしなくても問題はない。

Part 2: 5.2.2. Authorization server, 10.

shall require that all parameters are present inside the signed request object passed in the request or request_uri parameter;

全てのパラメーターは署名されたリクエストオブジェクト内に存在しなければならない。

実は OIDC Core では、リクエストオブジェクトの署名は必須とされていない。この文により、FAPI Part 2 ではリクエストオブジェクトに対する署名が必須となる。

また、全てのパラメーターをリクエストオブジェクトに入れなければならない点にも注意だ。OIDC Core では、リクエストパラメーターをリクエストオブジェクトの内部と外部のどちらに置いても、また、両方に置いてもかまわない。

Part 2: 5.2.2. Authorization server, 11.

may support the request object endpoint as described in section 7;

リクエストオブジェクトエンドポイントをサポートしてもよい。

FAPI Part 2 の『7. Request object endpoint』で、新たに『リクエストオブジェクトエンドポイント』というエンドポイントが定義される。それをサポートしてもよいという文だ。

Part 2: 5.2.2. Authorization server, 12.

shall require [RFC7636] with S256 as the code challenge method for public clients only, if it supports public clients;

Public クライアントに対して、PKCE を要求すること。Code challenge method は S256

Part 2: 5.2.2. Authorization server, 13.

shall require the request object to contain an exp claim; and

リクエストオブジェクトに exp クレームを含まなければならない。

OIDC Core では、リクエストオブジェクトに exp を含めることは要求されていない。FAPI Part 2 では exp クレームが必須となる。

Part 2: 5.2.2. Authorization server, 14.

shall authenticate the confidential client at the token endpoint using one of the following methods (this overrides FAPI part 1 clause 5.2.2.4):


  1. Mutual TLS for OAuth Client Authentication as specified in section 2 of [MTLS];


  2. private_key_jwt as specified in section 9 of [OIDC];

トークンエンドポイントのクライアント認証は次のどちらか(これは Part 1 の要求事項を上書き):


  1. MTLS の『2. Mutual TLS for OAuth Client Authentication』

  2. private_key_jwt

Part 1 と異なり、Part 2 ではクライアント認証方式として client_secret_jwt を使えない。


2.3. Part 2: Public クライアントに対する要求事項

Part 2 の『5.2.3. Public client』に、Public クライアントに対する要求事項が列挙されている。Part 1 の要求事項に従った上で、Part 2 対応の Public クライアントは次の要求事項に従う必要がある。

Part 2: 5.2.3. Public client, 1.

shall support [OAUTB] or [MTLS] as a holder of key mechanism; Note: [MTLS] shall be used with instance-specific keys and (self-signed) certificates to bind access tokens to the particular instance of a public client. It is NOT used as client authentication mechanisms.

Token Binding もしくは MTLS を holder of key mechanism としてサポートすること。MTLS の場合は、インスタンス毎に鍵と(自己署名)証明書を用意し、アクセストークンを特定のクライアントインスタンスと紐づけるようにすること。なお、クライアント認証で使われるわけではない。

書いてある通りだが、この文を読む前に、クライアント証明書をクライアント認証に使うこと(MTLS, 2. Mutual TLS for OAuth Client Authentication)と HoK に使うこと(MTLS, 3. Mutual TLS Client Certificate Bound Access Tokens)は異なるということを認識しておくこと。

Part 2: 5.2.3. Public client, 2.

shall include the request or request_uri parameter as defined in Section 6 of [OIDC] in the authentication request;

認証リクエストに request または request_uri を含めなければならない。

認可サーバーに対する要求事項にも挙げられているように、リクエストオブジェクトを使わなければならない。

Part 2: 5.2.3. Public client, 3.

shall request user authentication at LoA 3 or greater by requesting the acr claim as an essential claim as defined in section 5.5.1.1 of [OIDC];

ユーザー認証に LoA 3 以上を要求しなければならない。これは、acr クレームを必須(essential)として要求することにより行う。

acr クレームに限らず、クレームを必須として要求する場合、単純な acr_values リクエストパラメーターは使えない。かわりに、claims リクエストパラメーターを用いて、その値として JSON を渡し、その JSON 内の深いところに {"essential":true} と書かなければならない。下記は、urn:mace:incommon:iap:silver という ACR を必須として要求するために claims リクエストパラメーターに指定すべき JSON だ。

{

"id_token":
{
"acr":
{
"essential": true,
"values": ["urn:mace:incommon:iap:silver"]
}
}
}

ところで、この規程なのだが、実は、FAPI Part 2 をベースにしている英国オープンバンキングプロファイルでは、緩められる。essential として要求しなくてもよいのだ。おそらく意図的にそうしたわけではなく、オープンバンキングプロファイル作成時に参照した(コピー&ペースト元となった)FAPI 仕様のスナップショットに "by requesting the acr claim as an essential claim" という部分が入っていなかったからだろう。

FinTechLabs.io 社が作成している公式 FAPI 互換性テストスイートには、オープンバンキングプロファイルのテストも入っている。テストスイート自体のテストをするため、FinTechLabs.io 社は Authlete を使っているのだが、彼らがオープンバンキングプロファイルのテストを実行したとき、問題が起きた。Authlete の実装は厳密に FAPI に準拠しているため、「acr クレームが essential として要求されていない」というエラーを報告したのだが、オープンバンキングプロファイルの文脈では、これをエラーと見なさずにスルーしてほしいのだ。

「オープンバンキングプロファイルの仕様のほうを修正すべき(最新の FAPI 仕様に合わせるべき)」というのは真っ当な意見なのだが、「公式テストスイートでこれをエラーとして弾いてしまうと、現在の英国オープンバンキングの実装全てがことごとく公式テストをパスできなくなる。それは時期的に厳しい」という話が出たため、Authlete のほうに手を入れることにした。Authlete には FAPI に加え、OPEN_BANKING というプロファイルも用意され、もし OPEN_BANKING が有効になっている場合、FAPI Part 2 の文脈でも敢えて「acr クレームが essential として要求されていること」をチェックしないようにしたのだ。

private boolean isAcrEssentialRequired()

{
boolean required = false;

required |= mFapiRequirement.isAcrEssentialRequired();

// Open Banking Profile (OBP) is based on FAPI, but the specification
// does not require that the 'acr' claim be requested as essential.
// We here intentionally disable the check for the value of 'essential'
// when OBP is enabled because otherwise the official conformance test
// suite for OBP would fail.
if (isOpenBankingProfileEnabled())
{
required = false;
}

return required;
}

このような経緯もあり、実は Authlete は英国オープンバンキングのセキュリティープロファイルに準拠する製品として『Open Banking Security Profile Conformance』ページにリストされている。2019 年 1 月 21 日時点で Platform Vendor としてそこにリストされているのは、Authlete 社含めて世界に五社しかない(Authlete、Ping Identity、ForgeRock、Ozone、Ostia の五社)。

Part 2: 5.2.3. Public client, 4.

shall require JWS signed ID Token be returned from endpoints;

ID トークンを要求すること。

Part 2: 5.2.3. Public client, 5.

shall verify that the acr claim in an ID Token indicates that user authentication was performed at LoA3 or greater;

ID トークン内の acr が LoA 3 以上のユーザー認証が行われたことを示しているかどうか確認すること。

Part 2: 5.2.3. Public client, 6.

shall verify that the amr claim in an ID Token contains values appropriate for the LoA indicated by the acr claim;

ID トークン内の amr が、acr クレームが示す LoA にとって適切であるかどうか確認すること。

Part 2: 5.2.3. Public client, 7.

shall verify that the authorization response was not tampered using ID Token as the detached signature

ID トークンを Detached Signature として用い、認可レスポンスが改竄されていないことを確認すること。

後述の『5.2.5. JWT Secured Authorization Response Mode』で明示的にこの項目は言及されていないが、JARM を使う場合、この項目は適用外になると考えてよいだろう。

Part 2: 5.2.3. Public client, 8.

shall send all parameters inside the authorization request's signed request object

リクエストオブジェクト内に全てのパラメーターを入れること。

Part 2: 5.2.3. Public client, 9.

shall additionally send duplicates of the parameters/values using the OAuth 2.0 request syntax where required by the OAuth specification

加えて、OAuth 仕様に適合するように、重複してパラメーターを送ること。

リクエストオブジェクトに全てのパラメーターを入れるのであれば、request もしくは request_uri パラメーターが一つあれば事足りる。しかし、OAuth 2.0 / OIDC Core で必須とされているパラメーター(例えば client_idresponse_type)を省略してしまうと、そのリクエストは OAuth 2.0 / OIDC Core 準拠ではなくなってしまう。そのため、OAuth 2.0 / OIDC Core で必須とされているパラメーターは、リクエストオブジェクト内に既に入れていたとしても、リクエストオブジェクト外部にも重複して置かなければならない。

上記 1 〜 9 の他、5.2.3. の末尾には、「レスポンスに含まれる state のハッシュ値を計算し、それが ID トークンに含まれている s_hash の値と一致するかを検証すること」と書かれている。ただ、この文には、10 という番号が割り振られるべきである。fapi Issue 210 として Issue をあげておいた。


2.4. Part 2: Confidential クライアントに対する要求事項

Part 2 の『5.2.4. Confidential client』に、Confidential クライアントに対する要求事項が列挙されている。「PKCE 関連のものを除き(except for [RFC7636] support)」、5.2.3. に書かれている要求事項に従った上で、Part 2 対応の Confidential クライアントは次の要求事項に従う必要がある。

Part 2: 5.2.4. Confidential client, 1.

shall support [OAUTB] or [MTLS] as a holder of key mechanism (this overrides clause 5.2.3.1); Note: In case of confidential clients, [MTLS] can also be used as client authentication mechanism.

Token Binding もしくは MTLS を holder of key mechanism としてサポートすること(この規程は 5.2.3.1 を上書きする)。Confidential クライアントの場合、MTLS はクライアント認証方式として使うこともできる。

Part 2: 5.2.4. Confidential client, 2.

should require both JWS signed and JWE encrypted ID Tokens to be returned from endpoints to protect any sensitive personally identifiable information (PII) contained in the ID Token provided as a detached signature in the authorization response

ID トークンに含まれる個人特定情報を保護するため、ID トークンの暗号化も要求すべきである。

ID トークンの暗号化自体は OIDC Core のときから存在する機能である。暗号化アルゴリズムが非対称鍵系の場合、クライアントの公開鍵を認可サーバーで管理するか、クライアントの jwks_uri メタデータで示される場所からクライアントの JWK Set を取得する処理を実装しなければならない。ID トークンの署名だけであればサーバーの鍵だけで済むが、暗号化も対応しようとするとクライアント単位で鍵を扱わなければならないので、認可サーバーの実装には手間がかかる。ID トークンの暗号化に対応していない認可サーバーの実装が多いのはそのためである。

id_token_signature.png

id_token_encryption.png


2.5. Part 2: JARM

Part 2 の『5.2.5. JWT Secured Authorization Response Mode』は、Implementer's Draft 第二版で新規追加された JARM に関するセクションである。

JARM を用いると(response_modequery.jwtfragment.jwtform_post.jwtjwt のいずれかを指定すると)、レスポンスパラメーター群全体が一つの JWT にまとめられ、response というパラメーターの値として返ってくる。この JWT にはサーバーの署名が施されているので、クライアントは、署名を検証することにより、サーバーからのレスポンスが途中で改竄されていないことを確認できる。

Implementer's Draft 初版では、レスポンスの改竄を検出する仕組みは、ID トークンを Detached Signature として使う方法しか提供されていなかった。第二版では、これに加えて JARM を使うことができる。そのため、5.2.5. には「JARM を使う場合は 5.2.2. の 2 〜 4 の規程は適用されない。例えば、response_type の値が(id_token を含まない)code でもよい」と書かれている。

JARM を使う場合に適用外とすべき項目は 5.2.2. 2 〜 4 のみではなく、例えば明らかに 5.2.3. Public client, 7. の "shall verify that the authorization response was not tampered using ID Token as the detached signature"(ID トークンを Detached Signature として用い、認可レスポンスが改竄されていないことを確認すること)も適用外とされるべきだが、こういった仕様書内の不整合は追い追い修正されていくだろう。


2.5.1. JARM 関連のクライアントメタデータ

JARM の利用に先立って、クライアントは、自身の authorization_signed_response_alg メタデータに、レスポンス JWT の署名に使ってほしいアルゴリズムを指定しておく必要がある。レスポンス JWT の署名は必須とされているので、このメタデータが設定されていないにも関わらず response_mode リクエストパラメーターに *.jwt を指定すると、認可リクエストは失敗する。

レスポンス JWT を暗号化してほしい場合は、暗号化に関するメタデータである authorization_encrypted_response_algauthorization_encrypted_response_enc の設定も必要だ。非対称鍵系アルゴリズムを用いるのであれば、クライアントの公開鍵の設定も必要となる。


2.5.2. JARM 関連のサーバーメタデータ

JARM をサポートする認可サーバーは、ディスカバリー情報の response_modes_supported に、query.jwtfragment.jwtform_post.jwtjwt を一つ以上含んでいる。また、レスポンス JWT に使用するアルゴリズムについて、次のメタデータを持っている。

メタデータ
説明

authorization_signing_alg_values_supported
署名アルゴリズムでサポートしているもの

authorization_encryption_alg_values_supported
鍵用の暗号アルゴリズムでサポートしているもの

authorization_encryption_enc_values_supported
本文用の暗号アルゴリズムでサポートしているもの

JARM のフル機能をサポートしている認可サーバーのディスカバリー情報は次の内容を含むことになる。

"response_modes_supported": [

"query", "fragment", "form_post",
"query.jwt", "fragment.jwt", "form_post.jwt", "jwt"
],

"authorization_signing_alg_values_supported": [
"HS256", "HS384", "HS512", "RS256", "RS384", "RS512",
"ES256", "ES384", "ES512", "PS256", "PS384", "PS512"
],

"authorization_encryption_alg_values_supported": [
"RSA1_5", "RSA-OAEP", "RSA-OEAP-256",
"A128KW", "A192KW", "A256KW",
"dir",
"ECDH-ES", "ECDH-ES+A128KW", "ECDH-ES+A192KW", "ECDH-ES+A256KW",
"A128GCMKW", "A192GCMKW", "A256GCMKW",
"PBES2-HS256+A128KW", "PBES2-HS384+A192KW", "PBES2-HS512+A256KW"
],

"authorization_encryption_enc_values_supported": [
"A128CBC-HS256", "A192CBC-HS384", "A256CBC-HS512",
"A128GCM", "A192GCM", "A256GCM"
],


2.6. Part 2: リクエストオブジェクトエンドポイント

認可リクエストでリクエストオブジェクトを用いる場合、request リクエストパラメーターでリクエストオブジェクトの実体を直接渡すか、もしくは、request_uri リクエストパラメーターでリクエストオブジェクトを間接的に渡す。

request_uri を使う場合は、クライアント開発者は別途サーバーを用意し、そこにリクエストオブジェクトの実体を置くことになる。この、リクエストオブジェクトのホスティングをするサーバーを、認可サーバー自身にやらせよう、という発想がある。

Part 2 の『7. Request object endpoint』では、新たに『リクエストオブジェクトエンドポイント』というエンドポイントが定義される。リエクストオブジェクトエンドポイントは、リクエストオブジェクトの実体を認可サーバーに登録するためのエンドポイントだ。登録を受け付けたリクエストオブジェクトエンドポイントは、そのリクエストオブジェクトを認可サーバー実装内のどこかに保存したあと、そのリクエストオブジェクトを一意に識別する URI を生成し、JSON に入れて返す。

下記は、FAPI Part 2 の『7.2. Request』と『7.3. Successful response』に載っているリクエストとレスポンスの例だ。

POST https://as.example.com/ros/ HTTP/1.1

Host: as.example.com
Content-Type: application/jws
Content-Length: 1288

eyJhbGciOiJSUzI1NiIsImtpZCI6ImsyYmRjIn0.ew0KICJpc3MiOiA
(... abbreviated for brevity ...)
zCYIb_NMXvtTIVc1jpspnTSD7xMbpL-2QgwUsAlMGzw

HTTP/1.1 201 Created

Date: Tue, 2 May 2017 15:22:31 GMT
Content-Type: application/json

{
"iss": "https://as.example.com/",
"aud": "s6BhdRkqt3",
"request_uri": "urn:example:MTAyODAK",
"exp": 1493738581
}

認可サーバーがリクエストオブジェクトエンドポイントを提供する場合、そのディスカバリー情報には request_object_endpoint というメタデータが含まれる。


2.7. Part 2: セキュリティー上の考慮事項

Part 2 の『8. Security considerations』に、セキュリティー上の考慮事項が列挙されている。要約は下記の通り。

要約

8.1
本仕様は RFC 6749Section 10 および RFC 6819 にあるセキュリティー上の考慮事項を参照する。

8.2
API は、Certificate Binding または Token Binding されたアクセストークンのみサポートすること。

8.3.1
認可サーバー毎に異なるリダイレクト URI を用意すべきだが、そうしていないクライアントが多い。

8.3.2
攻撃者により偽のトークンエンドポイントを信じこまされると、認可コードとクライアントシークレットを攻撃者に渡してしまう。

なお、8.3.2 には次のような文章が含まれているが、


When the FAPI client uses [MTLS] or [OAUTB], the authorization code is bound to the TLS channel, any phished client credentials and authorization codes submitted to the token endpoint cannot be used since the authorization code is bound to a particular TLS channel.


Part2-5.2.2-5 に言及したときに触れたように、この文には問題がある。「FAPIでは、MTLS もしくは Token Binding により、認可コードは特定の TLS チャネルに結び付けられる」と書いてあるものの、これは仕様策定者達が意図したものではない。この文はいつか修正されるだろう。

要約

8.3.3
IdP mix-up 攻撃への対策としてハイブリッドフローを用いることができる。

8.3.4
攻撃者により偽のリクエストオブジェクトエンドポイントを信じこまされると、秘匿すべき情報を含むリクエストオブジェクトを攻撃者に渡してしまう。

8.3.5
FAPI Part 2 では、アクセストークンは TLS チャネルに紐づくので、盗まれても利用できない。

8.4.1
RFC 6749 では認可リクエスト・レスポンスの完全性(integrity)は保証されず、攻撃者が変更できてしまう。

8.4.2
リクエストオブジェクトを利用することで、認可リクエストの改竄を防ぐことができる。

8.4.3
ハイブリッドフローを利用してハッシュ値を検証することにより、認可コード等の認可レスポンスパラメーターが改竄されていないことを確認できる。


2.8. Part 2: TLS

Part 2 の『8.5. TLS considerations』により、TLS 通信の暗号スイートは次の 4 つに限定される。


  1. TLS_DHE_RSA_WITH_AES_128_GCM_SHA256

  2. TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256

  3. TLS_DHE_RSA_WITH_AES_256_GCM_SHA384

  4. TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384

ただし、認可エンドポイントについては、Web ブラウザの相互運用性の視点から、最新の BCP 195 で許可されている暗号スイートを追加で許容してもよい。


2.9. Part 2: JWS アルゴリズム

JWS の署名アルゴリズムは、JWA の『3.1. "alg" (Algorithm) Header Parameter Values for JWS』に、none も含めて 13 個が列挙されている。Part 2 の『8.6. JWS algorithm considerations』では、これを PS256ES256 に限定している。RS256none については、それぞれ「使うべきではない(should not use)」、「使ってはならない(shall not use)」と明示的に述べている。

OIDC に対応する認可サーバーは、次の場所で JWS を使っている。

仕様
用途

1
RFC 7523

client_assertion パラメーター

2
OIDC Core
ID トークン

3
OIDC Core
リクエストオブジェクト

4
OIDC Core

UserInfo エンドポイントからのレスポンス

5
JARM
レスポンス JWT

更新系 API 用のアクセストークンを取得するための認可リクエストにおいては、上記の場所(UserInfo エンドポイントを除く)で使われる署名アルゴリズムは PS256ES256 に限定される。

また、CIBA のバックチャネル認証リクエストには、OIDC Core の認証リクエストと同じように request リクエストパラメーターが存在しており、こちらも、リクエストパラメーター群を JWT にまとめて渡す仕組みとなっている。今後議論が進む CIBA-FAPI プロファイルにおいて、request に渡す JWT の署名アルゴリズムについて何かしらの言及がなされるであろう。


3. FAPI 実装

ここでは、FAPI 実装に関するトピックを幾つか取り上げる。


3.1. 参照系と更新系の区別

参照系 API 用のアクセストークンを取得するための認可リクエスト・トークンリクエスト、およびリソースサーバーの参照系 API そのものについては、FAPI Part 1: Read-Only API Security Profile の規程が適用される。

更新系 API 用のアクセストークンを取得するための認可リクエスト・トークンリクエスト、およびリソースサーバーの更新系 API そのものについては、FAPI Part 2: Read and Write API Security Profile の規程が適用される。

リソースサーバーの API は、自分自身が参照系なのか更新系なのか分かっているので、どちらの Security Profile に従えばよいのかは明白である。

一方、認可サーバーの認可エンドポイントは、届いた認可リクエストが、参照系 API 用アクセストークンを取得するためのものなのか、それとも更新系 API 用アクセストークンを取得するためのものなのか、はたまた、FAPI とは無関係の API 用のアクセストークンを取得するためのものなのか、どうやって区別すればよいのだろうか?

実は、仕様は区別方法について一切言及していない。

単純な解決手段は、「全ての認可リクエストを FAPI 更新系 API 用のアクセストークンを取得するためのものとみなす」、というものである。実は英国オープンバンキングはそうなっている。このような決め打ちの実装は、単発のシステム開発であれば許容できるかもしれない。

しかしながら、汎用的な認可サーバー実装では、API を更新系か参照系のどちらか(またはその以外)に固定するのは賢明とは言えない。なぜなら、あまりにシステム設計の柔軟さを損ねてしまうからだ。そのため、汎用ソリューションの場合、認可リクエストが参照系/更新系/その以外かどうかは、動的に判断するように実装したほうがよい。

では、どうやって動的に区別するか? これは考えていくと行き着く方法は一つで要求されているスコープを見て参照系/更新系/その以外を区別することになる。

※:実は、アクセス予定のリソースを示す resource という名のリクエストパラメーターを認可リクエストに追加するための『Resource Indicators for OAuth 2.0』という仕様の草案が存在する。この resource を使う手も考えられる。ただし、この仕様に対する支持が広がるかどうかは現時点では不明である。

例えば、readwrite というスコープ群を用意し、参照系 API にアクセスするには read スコープが必要、更新系 API にアクセスするには write スコープが必要というルールを定め、API をその通りに実装しておく。こうしておけば、認可エンドポイントの実装は、認可リクエストの scope パラメーターに(1)write が含まれれば更新系とみなして FAPI Part 2 の規程を適用、(2)write は含まれないが read が含まれていれば参照系とみなして FAPI Part 1 の規程を適用、(3)readwrite も含まれていなければその他とみなして普通の OAuth 2.0 / OIDC の規程を適用、とすることで、実行時に動作を動的に切り替えることができる。

スコープで判断するとして、その実装はどうするか? 例えば、スコープ名が read で始まったら参照系 API 用スコープとみなすようにするか? しかしこれだと、スコープ名に縛りがかかり過ぎて、筋が悪そうだ。では Authlete はどのようなアプローチをとったか?

Authlete はまず、スコープに任意の属性群を紐づけるための汎用的な仕組みを実装した。その後、属性名 fapi を特別扱いし、その値が r であれば参照系(Read-Only)、rw であれば更新系(Read and Write)と判断するようにした。

FAPI 対応の Authlete(バージョン 2.0 以降)に対応する Web コンソールでは、スコープに属性を紐づける UI を提供している。次のスクリーンショットは、fapi=r という属性を持つ read スコープを定義している。

scope-creation.png

スコープを作成する UI。
属性 fapi=r を持つ read スコープの定義例。

認可リクエストをパースするための Authlete API である /api/auth/authorization は、認可リクエストの scope パラメーターに含まれるスコープ群の属性群を全て調べ、fapi=rw が一つでも含まれていれば FAPI 更新系、fapi=rw は含まれていないが fapi=r が一つ以上含まれていれば FAPI 参照系とみなす。

ここで紹介した話は、2018 年 7 月 24 日に東京金融ビレッジで開催した『Financial APIs Workshop』における発表資料『Authlete FAPI Implementation Part 2』に記載されている。同資料には、「リクエストオブジェクト内外のパラメーターの一致」に関する、かなりマニアックな話題も載っている。


3.2. Mutual TLS

Mutual TLS と言ったときに、次の三つの意味があることは既に説明した。


  1. クライアント証明書の提示を伴う TLS 通信

  2. クライアント証明書を用いるクライアント認証

  3. Certificate Binding

1 は、API 管理ソリューションが扱う部分である。しかしながら、2 と 3 については、必ずしも API 管理レイヤーで扱う必要はない。むしろ、良いシステム設計のためには全く別システムとして構築したほうがよい。

Authlete は、その独特なアーキテクチャーにより、API 管理レイヤーの仕事は一切おこなわない。つまり、1 のレイヤーには全く関与しない。一方で、2 と 3 の機能をサポートする。これにより、Authlete を使えば、好きな API 管理ソリューションを使いつつ FAPI で要求される MTLS(OAuth 2.0 Mutual TLS Client Authentication and Certificate Bound Access Tokens)をサポートすることができる。実際に、Microsoft/API Management や Google/Apigee と Authlete を組み合わせて MTLS が実現できることは確認済みだ。AWS API Gateway はまだ試していないが、どんな API 管理ソリューションだとしても、TLS 通信で使われたクライアント証明書を取り出す機能さえ提供していれば、Authlete と組み合わせて使うことで、FAPI の MTLS をサポートすることができる。

API 管理ソリューションが直接 2 と 3 の機能を実装するまでには時間がかかるだろうし、それに、直接サポートするのは良い設計とも言えない。現時点では、大手クラウドベンダーの API 管理ソリューションを使うのであれば、Authlete を使うのが最適解だ。

MTLS の実装について、業界では有名なソフトウェアエンジニアであり、また、Authlete 社のプリンシパル・アーキテクトであるジャスティン・リッチャー(Justin Richer)が話している貴重な動画がこちらだ。

"Authlete FAPI Enhancements" by Justin Richer in July 2018

"Authlete FAPI Enhancements" by Justin Richer in July 2018

2018 年 7 月 24 日に東京金融ビレッジで開催した『Financial APIs Workshop』の一コマで、発表で彼が使用した資料は『Authlete FAPI Implementation Part 1』に置いてある。

ちなみに、彼の著書『OAuth 2 in Action』の日本語訳が『OAuth 徹底入門』というタイトルで 2019 年 1 月 30 日に翔泳社から販売開始される。監修は Authlete 社だ。

OAuth_2_in_Action-Cover.jpeg
OAuth徹底入門-Cover.png

OAuth 2 in Action
OAuth 徹底入門


3.3. アクセストークンの有効期限

FAPI 仕様には関係ないのだが、銀行 API の文脈で「送金処理用のアクセストークンの有効期限を短くしたい」という相談を頻繁に受けるので、ここで取り上げる。

この処理は、「認可リクエストの scope リクエストパラメーターに送金処理に必要な権限を示す特別なスコープが含まれていた場合に、その認可リクエストの結果として発行されるアクセストークンの有効期限を、他の場合のときよりも短くする」ことで実現できる。例えば、送金 API が remit というスコープを要求するとした場合、このスコープが認可リクエストに含まれている場合だけ、特別にアクセストークンの有効期限を短くするのだ。

Authlete は、スコープ属性名 access_token.duration を特別処理することで、この機能を実現する。

認可リクエストに含まれるスコープ群の全属性を調べ、access_token.duration という属性名を持つ属性の属性値の中で、一番小さいものをアクセストークンの有効期限として用いる。access_token.duration という属性名を持つ属性が一つも存在しない場合は、認可サーバー単位で設定されているアクセストークン有効期限をデフォルト値として用いる。access_token.duration で求められた有効期限よりもデフォルト値の有効期限のほうが小さい場合、デフォルト値のほうが用いられる。

例えば、アクセストークンの有効期限を 300 秒とする remit スコープの定義は次のようになる。

access_token_duration.png

アクセストークンの有効期限を 300 秒とする例

同様にして、refresh_token.duration という属性名でリフレッシュトークンの有効期限も設定することができる。


3.4. アクセストークンと取引詳細情報の紐付け

これも FAPI 仕様には関係ないが、といいつつ欧州の金融関連文書で言及があるので無関係とは言えないが、銀行 API の文脈で「取引毎にアクセストークンを発行する。そのアクセストークンに取引詳細情報を紐付けたい」という相談を頻繁に受けるので、ここで取り上げる。

この機能は、「3.3. アクセストークンの有効期限」で紹介したスコープ単位の属性では実現できない。アクセストークン単位で個別に情報を紐づける必要がある。Authlete には、任意のキー・バリューの組をアクセストークンに紐づける仕組みが昔から存在している。詳細は『OAuth 2.0 / OIDC 実装の新アーキテクチャー』の『7.3. アクセストークンと任意データ』を参照してほしい。

アクセストークンに任意のキー・バリューの組みを紐づけることができるので、そこに例えば送金先や送金金額に関する情報を書き込むこともできるが、あまりお勧めできない。そうではなく、取引情報は別のデータベースに保存しておき、そのレコードの一意識別子だけをアクセストークンに紐づけるようにするのがよい。


おわりに

英国オープンバンキングは、FAPI の仕様策定作業が真っ最中のときに FAPI の採用を決めた。その英国オープンバンキングも、実運用に入ってから既に 1 年が経過した。実績を見て、オーストラリアも FAPI ベースの API エコシステムを構築することを決めた。FAPI の仕様改定作業は今後も続くことが見込まれ、枯れた仕様とはまだまだ言えないが、世界の専門家が策定する世界最先端の API セキュリティー技術である FAPI を、これらの国々は積極的に取り入れ、前に進んでいる。

一方の日本では、FAPI Implementer's Draft 第二版が承認されたあとの昨年末、米国系クラウドベンダーに転職したばかりの若い技術営業が「FAPI はまだ仕様が固まっていないので、我が社は対応しません(キリッ」という発言をしていた。それがその会社の総意だとは思えないが、その発言を伝え聞いたときに、英国と日本の金融業界の違いを端的に示していると思った。

英国は現在、金融業界全体がスタートアップ的なのだ。まだ不確定要素を含む FAPI を採用し、それを共に育てながら、あるべき姿に向かって挑戦を続けている。一方の日本は、不確定要素がなくなって実績十分になるまで様子見を決め込んでおり、大企業病的なのだ。

ただ、日本のこの状況は、今後変わる。というか、変える。変えるための仕込みを今やっている。目論見通り進むかどうかはもちろん不明だが、FAPI について世界有数の知見と実装を持つ Authlete 社が挑戦しなければ、他に誰がやるというのか。使命感が芽生えつつある。