LoginSignup
236
228

More than 1 year has passed since last update.

実装者による Financial-grade API (FAPI) 解説

Last updated at Posted at 2019-01-21

注記: 2021 年 3 月に公開された FAPI 1.0 最終版に対応するため、本記事の内容を大幅に更新しました。タイトルも『世界最先端の API セキュリティー技術、実装者による『FAPI(Financial-grade API)』解説』から『実装者による Financial-grade API (FAPI) 解説』に変更しました。本記事の英語版は "Financial-grade API (FAPI), explained by an implementer" です。

はじめに

Financial-grade API(通称 FAPI; ファピ)は、OpenID FoundationFinancial-grade API ワーキンググループが策定した技術仕様です。OAuth 2.0OpenID Connect(以降 OIDC)を基盤とし、より高い API セキュリティーを必要とする金融業界および他の様々な業界のため、追加の技術要求事項を定めています。

fapi-stack_ja.png

歴史

Implementer's Draft 1(実装者向け草稿第一版)

FAPI 仕様の最初のバージョンは 2017 年に公開されました。このバージョンは Implementer's Draft 1(ID1)と呼ばれています。

Implementer's Draft 2(実装者向け草稿第二版)

二番目のバージョンは 2018 年 10 月に公開されました。このバージョンは Implementer's Draft 2(ID2)と呼ばれています。多様な業界での採用を促すため、このバージョンで仕様の名称が『Financial API』から『Financial-grade API』へと変更されました。

Final(最終版)

最終版は 2021 年 3 月に公開されました。このバージョンで、FAPI 仕様の中心となる二つのパートである『Part 1: Read-Only Security Profile』と『Part 2: Read and Write API Security Profile』がそれぞれ、『Part 1: Baseline Security Profile』と『Part 2: Advanced Security Profile』に名称変更されました。

FAPI 2.0

FAPI ワーキンググループは、FAPI 仕様の次のバージョンである FAPI 2.0 の議論を開始しています。2021 年 3 月 31 に公開された FAPI FAQ は FAPI 2.0 に言及しています。FAPI 2.0 を構成する新しい技術要素である PAROAuth 2.0 Pushed Authorization Requests)や RAROAuth 2.0 Rich Authorization Requests)、DPoPOAuth 2.0 Demonstrating Proof-of-Possession at the Application Layer)などを Authlete が既に実装しているため、"Are there FAPI 2.0 implementations?" という質問に対する回答の中で Authlete が言及されています。

fapi-history_ja.png

仕様

FAPI 仕様の中心となるのは Part 1 と Part 2 です。以前のバージョンおよび最終バージョンは下記のリンクから参照できます。

Implementer's Draft 1(Part 1: 2017 年 2 月 2 日 / Part 2: 2017 年 7 月 17 日)

Implementer's Draft 2(2018 年 10 月 17 日)

Final(2021 年 3 月 12 日)

加えて、2019 年 8 月には FAPI-CIBA プロファイルと呼ばれる技術仕様も公開されました。この仕様は、FAPI と CIBAClient Initiated Backchannel Authentication)を同時に使う際に適用する追加要件を定めています。

CIBA および FAPI-CIBA プロファイルについては次の記事をご参照ください。

ciba_ja.png

認定プログラム

FAPI OpenID Provider 認定プログラム

FAPI OpenID Provider 認定プログラムは 2019 年 4 月 1 日に開始しました(アナウンス)。開始日に認定を受けたベンダーは 2 社で、その一つが本記事執筆者()が創業した Authlete 社です。

certified_fapi_ops_20190401.png
2019 年 4 月 1 日時点の認定 FAPI OpenID Provider

当時から 2 年が経過し、今では 30 以上の製品や事業者が FAPI OpenID Provider に認定されています。

現時点(2021 年 4 月)では FAPI 1.0 最終版の認定プログラムは始まっていませんが、Authlete 2.2 は既に FAPI 最終版をサポートしています。詳細は 2021 年 2 月 4 日に公表したお知らせリリースノートをご参照ください。

FAPI-CIBA OpenID Provider 認定プログラム

FAPI-CIBA OpenID Provider 認定プログラムは 2019 年 9 月 16 日に開始しました(アナウンス)。開始日に認定を受けたのは Authlete のみでした。

certified_fapi_ciba_ops_20190916.png
2019 年 9 月 16 日時点の認定 FAPI-CIBA OpenID Provider

現時点(2021 年 4 月)では、Authlete 社を含め 3 つの製品が FAPI-CIBA OpenID Provider に認定されています。

前提知識

基本仕様群

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

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

jws-compact-serialization_ja.png
JWS Compact Serialization

加えて、2015 年に策定された PKCERFC 7636)は、現在では RFC 6749 と RFC 6750 に並ぶ OAuth 2.0 の基本仕様扱いされています。

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

これらの仕様書を読むにあたり、次の解説記事群が参考になると思います。

Mutual TLS

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

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

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

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

client_authentication_at_token_endpoint_ja.png

クライアント認証方式は幾つか存在し、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_basic_ja.png
client_secret_basic
client_secret_post_ja.png
client_secret_post

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

client_authentication_using_jwt_ja.png
JWT を用いたクライアント認証

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

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

これら 2 つは、クライアントとトークンエンドポイントとの間の TLS 接続で使われたクライアント証明書をクライアント認証に利用します。

client_certificate_for_client_authentication_ja.png

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

  • 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 の証明書ではなく、自己署名証明書をクライアント証明書として用います。このクライアント認証方式を用いるためには、クライアントは、当該自己署名証明書・公開鍵を事前にサーバーに登録しておかなければなりません。

次の表は、FAPI 仕様で言及されているクライアント認証方式群を示しています。

クライアント認証方式 必要なデータ 補足
client_secret_basic クライアント ID、クライアントシークレット ベーシック認証
client_secret_post クライアント ID、クライアントシークレット POST リクエストのフォームパラメーターとして
client_secret_jwt JWT クライアントシークレットで署名
private_key_jwt JWT 秘密鍵で署名
tls_client_auth クライアント証明書 PKI 証明書
self_signed_tls_client_auth クライアント証明書 自己署名証明書

クライアント認証の詳細については『OAuth 2.0 クライアント認証』をご参照ください。また、X.509 証明書の詳細にご興味があれば『図解 X.509 証明書』をご参照ください。

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

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

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

この概念は『Proof of Possession』(PoP)と総称されており、FAPI では Mutual TLS を唯一の PoP の選択肢として挙げています(過去の版では Token Binding も PoP 手法として挙げられていましたが最終版で削除されました)。この文脈における Mutual TLS は、RFC 8705 の『3. Mutual-TLS Client Certificate-Bound Access Tokens』で説明されている技術をさします。

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

私:「御社の API 管理ソリューションは(PoP としての)Mutual TLS をサポートしていませんよね?」
中の人:「いや、(TLS 通信時にクライアント証明書を要求することはできるので)Mutual TLS はサポートしていますよ。」

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

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

certificate-binding_ja.png

Certificate Binding は、クライアント証明書にアクセスできさえすればいいので、比較的実現が容易な PoP 手法です。一方の 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』(期限切れドラフト)は、これらの RFC 群を土台として OAuth 2.0 のトークン群に Token Binding を適用する方法を定める仕様です。

注意:将来の実現可能性が低いことから、Token Binding は FAPI 最終版から削除されました。

JARM

JARM は FAPI Implementer's Draft 2 と同時期に承認された新しい仕様です。JARM は FAPI Part 2 で参照されています。

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

  • query.jwt
  • fragment.jwt
  • form_post.jwt
  • jwt

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

例えば、認可コードフローにおける従来の認可レスポンスは次のようになっています。code レスポンスパラメーターと state レスポンスパラメーターが別れて含まれています。

HTTP/1.1 302 Found
Location: https://client.com/callback?code={CODE}&state={STATE}

一方、認可リクエストに response_mode=query.jwt が追加された場合、認可レスポンスは次のようになります。

HTTP/1.1 302 Found
Location: https://client.com/callback?response={JWT}

jarm_example_ja.png

認可レスポンスの JWT はサーバーの鍵によって署名されているので、クライアントは、その JWT の署名を検証することにより、レスポンスが改ざんされていないことを確認することができます。

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

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

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

下記は、Authlete のクライアント管理用 Web コンソールにおける、JARM 関連設定項目のスクリーンショットです。

jarm_client_metadata_ja.png

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"
],

Part 1: Baseline

前提知識の紹介が終わったので、本題の FAPI の解説に入ります。まず、Baseline セキュリティプロファイルを定義する Part 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 のフローとクライアントタイプの関係は、OAuth 2.0 に詳しい方でも誤解されていることがよくあります。RFC 6749 が明示的に禁止しているのは、「Public クライアント」と「クライアントクレデンシャルズフロー」の組み合わせのみです。他の組み合わせは許されています。詳細は『OAuth 2.0 のフローとクライアントタイプの関係』をご参照ください。

フロー Confidential クライアント Public クライアント
認可コードフロー OK OK
インプリシットフロー OK OK
リソースオーナーパスワードクレデンシャルズフロー OK OK
クライアントクレデンシャルズフロー OK NG

参考までにですが、CIBA で定義されているバックチャネル認証リクエストを投げることを許されているのは、Confidential クライアントのみです。

フロー Confidential クライアント Public クライアント
CIBA POLL モード OK NG
CIBA PING モード OK NG
CIBA PUSH モード OK NG
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 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 は利用できないので注意してください。

クライアント認証メソッド 使用
client_secret_basic NG
client_secret_post NG
client_secret_jwt OK
private_key_jwt OK
tls_client_auth OK
self_signed_tls_client_auth OK
Part 1: 5.2.2. Authorization server, 5.
shall require and use a key of size 2048 bits or larger if RSA algorithms;
RSA アルゴリズムを用いる場合、キーサイズは 2048 ビット以上
Part 1: 5.2.2. Authorization server, 6.
shall require and use a key of size 160 bits or larger if elliptic curve algorithms are used;
楕円曲線アルゴリズムを用いる場合、キーサイズは 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 て定義されるリクエストパラメーター群が必要。コードチャレンジメソッドは S256

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

authorization-code-interception-attack.png
認可コード横取り攻撃

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 to an appropriate Level of Assurance for the operations the client will be authorized to perform on behalf of the user;
適切な LoA のユーザー認証をしなければならない。

認可処理時に実行されるユーザー認証処理が適切な LoA(Level of Assurance)を満たすことが要求されます。ID1 と ID2 では、X.1254(Entity authentication assurance framework)で定義されている LoA(Level of assurance)の 2 以上を満たすことが求められていました。しかし、最終版では要求内容はより抽象的になりました(「LoA2」から「適切な LoA」へと変更されました)。

参考までに、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 approval by the user to authorize the requested scope if it has not been previously authorized;
過去に認可を得ていないスコープについては、ユーザーの承認を明示的に得なければならない。

当然ですね。

Part 1: 5.2.2. Authorization server, 13.
shall reject an authorization code (Section 1.3.1 of RFC6749) if it has been previously used;
以前使用されたことのある認可コードは拒絶しなければならない。

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

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 固有の要求事項ではありません。OAuth 2.0 サポートを謳う全ての認可サーバーの実装は RFC 6749 の Section 4.1.4 に従っていなければなりません。

Part 1: 5.2.2. Authorization server, 15.
shall return the list of granted scopes with the issued access token if the request was passed in the front channel and was not integrity protected;
リクエストがフロントチャネルを経由し、完全性が保護されていない場合、付与されたスコープのリストを発行されたアクセストークンと共に返さなければならない。

RFC 6749 では、認可サーバーがクライアントアプリケーションにアクセストークンを発行する際、そのアクセストークンに紐付けられたスコープ群のリストをアクセストークンと共にクライアントに返すかどうかは、クライアントが元々要求したスコープ群と結果として付与されたスコープ群が異なる場合を除き、任意です(RFC 6749, 5.1. Successful Response)。しかし、FAPI では、リクエストがフロントチャネルを経由し、完全性が保護されていない場合、(要求したスコープと付与されたスコープが同一だとしても)付与されたスコープ群のリストは常に応答に含まれます。

ここでの「完全性の保護」とは、リクエストオブジェクト(OIDC Core Section 6 または JAR)の使用を意味しています。

Part 1: 5.2.2. Authorization server, 16.
shall provide non-guessable access tokens, authorization codes, and refresh token (where applicable), with sufficient entropy such that the probability of an attacker guessing the generated token is computationally infeasible as per RFC 6749 Section 10.10;
アクセストークン、認可コード、リフレッシュトークンは、十分なエントロピーを持ち、推測不能なものであること。

ID2 ではアクセストークンは最低 128 ビットのエントロピーを持っていなければならないとされていましたが、最終版ではエントロピーの最小値について具体的な値に言及することは避け、単に「十分なエントロピー」という表現になっています。

Part 1: 5.2.2. Authorization server, 17.
should clearly identify the details of the grant to the user during authorization as in 16.18 of OIDC;
認可処理中に、付与する権限の詳細をユーザーに明示すべきである。

例えばクライアントが payment スコープを要求したとします。典型的な認可ページでは、クライアントアプリケーションが payment スコープを要求したことを伝えるのみでしょう。しかし、海外の金融業界の最近の規制では、詳細をユーザーに説明することが求められます。例えば、payment スコープの目的に関する情報、送金額、などです。一般的に、規制は認可内容が個別具体的であることを求めます。

この目的のため、英国オープンバンキングは『Lodging Intent』を開発しました。この仕組みでは、(a)クライアントアプリケーションが認可の詳細をあらかじめ認可サーバーに登録し、(b)認可サーバーは登録された詳細を表すインテント ID を発行し、(c)クライアントアプリケーションはそのインテント ID を用いて認可リクエストをおこないます。結果として、認可サーバーは認可リクエストの詳細情報を含む認可ページを生成することができます。

この Lodging Intent パターンを標準仕様として利用できるようにするため、OpenID Foundation は二つの仕様、OAuth 2.0 Pushed Authorization Requests (PAR) と OAuth 2.0 Rich Authorization Requests (RAR) を策定しました。これらの仕様については後ほど再度言及します。

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

PKI(Public Key Infrastructure)で言うところの CRL(Certificate Revocation List)や OCSP(Online Certificate Status Protocol)に相当する仕組みを実装・運用しない限り、内包型のアクセストークン(典型的には JWT 型のアクセストークン)を取り消すことはできないので、注意が必要です。CRL/OCSP 相当の仕組みを提供しないシステムは、アクセストークンの取り消しを諦めるという決定をしたと言えます。この場合、アクセストークン漏洩の被害を和らげるために、アクセストークンの有効期限を十分に短くしなければなりません。詳細については『OAuth アクセストークンの実装に関する考察』を参照してください。

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 リクエストパラメーターも指定されていた場合、その値も一致しなければなりません。

client_ids_in_client_assertion.png

Part 1: 5.2.2. Authorization server, 20.
shall require redirect URIs to use the https scheme;
リダイレクト URI のスキームは https でなければならない。

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

Part 1: 5.2.2. Authorization server, 21.
should issue access tokens with a lifetime of under 10 minutes unless the tokens are sender-constrained; and
アクセストークンが送信者限定でない限り、その有効期間は 10 分以内でなければなりません。

この要求事項は最終版で追加されました。ここで「送信者限定(sender-constrained)」とは、アクセストークンがクライアント証明書に紐付いている(MTLS)こと意味します。

Part 1: 5.2.2. Authorization server, 22.
shall support OIDD, may support RFC8414 and shall not distribute discovery metadata (such as the authorization endpoint) by any other means.
OIDD をサポートしなければなず、RFC 8414 のサポートは任意であり、他の方法で(認可エンドポイントなどの)ディスカバリーメタデータを配布してはならない。

この要求事項は最終版で追加されました。ここで OIDD は OpenID Connect Discovery 1.0 をさします。そのため、FAPI 用の認可サーバーでは OIDD の Section 4 で定義されている『ディスカバリーエンドポイント』を実装する必要があります。

Part 1: 5.2.2.1. Returning authenticated user's identifier
Further, if it is desired to provide the authenticated user's identifier to the client in the token response, the authorization server:
さらに、認証されたユーザーの識別子をトークンリクエストに含めてクライアントに返すことが求められている場合、認可サーバーは:

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

Part 1: 5.2.2.1. Returning authenticated user's identifier, 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, 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, 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, 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, 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, 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 の仕様に従ってください」ということになります。FAPI 固有の要求事項はありません。

Part 1: 5.2.2.2. Client requesting openid scope
If the client requests the openid scope, the authorization server
  1. shall require the nonce parameter defined in Section 3.1.2.1 of OIDC in the authentication request.
クライアントが openid スコープを要求している場合、認可サーバーは
  1. OIDC の Section 3.1.2.1 で定義されている nonce パラメーターを要求しなければならない。

OIDC の Section 3.1.2.1(認可コードフロー)では nonce は任意とされています。一方、Section 3.2.2.1(インプリシットフロー)では nonce は必須とされています。

FAPI では、scopeopenid が含まれている場合、認可コードフローの場合でも nonce が要求されます。

Part 1: 5.2.2.3. Clients not requesting openid scope
If the client does not requests the openid scope, the authorization server
  1. shall require the state parameter defined in Section 4 of RFC6749
クライアントが openid スコープを要求していない場合、認可サーバーは
  1. RFC 6749 の Section 4 で定義されている state パラメーターを要求しなければならない。

RFC 6749 では state パラメーターは任意とされています。FAPI では、scopeopenid が含まれていない場合、state は必須となります。

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

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

Part 1: 5.2.3. Public client, 1.
shall support RFC7636;
RFC 7636 をサポートしなければならない。

RFC 7636 は PKCE のことです。

Part 1: 5.2.3. Public client, 2.
shall use S256 as the code challenge method for the RFC7636;
コードチャレンジメソッドに 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.
(withdrawn); and
(撤回)

"(withdrawn)" は、以前の FAPI バージョンに存在した要求事項が撤回されたことを意味します。この後にも "(withdrawn)" が何度か登場します。

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 パラメーターを含まなければならない。
Part 1: 5.2.3. Public client, 10.
shall verify that the scope received in the token response is either an exact match, or contains a subset of the scope sent in the authorization request; and
トークンレスポンス内の scope が認可リクエストの scope と正確に一致すること、もしくは、サブセットになっていることを検証しなければならない。
Part 1: 5.2.3. Public client, 11.
shall only use Authorization Server metadata obtained from the metadata document published by the Authorization Server at its well known endpoint as defined in OIDD or RFC 8414.
サーバーメタデータについては、ディスカバリーエンドポイントから取得したもののみを使用すること。

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, and
  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 を扱う場合に関係してきます。

Part 1: 保護リソースに対する要求事項

Part 1 の『6.2.1. Protected resources provisions』には、保護リソースに対する要求事項が列挙されています。

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 ヘッダーによりアクセストークンを受け取れなければなりません。

GET 保護リソース?パラメーター群 HTTP/1.1
Host: リソースサーバー
Authorization: Bearer アクセストークン
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 access to 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 ヘッダーであることに注意してください。

HTTP/1.1 400 Bad Request
WWW-Authenticate: Bearer error="エラーコード",
  error_description="エラーの説明",
  error_uri="エラーの詳細説明が書かれたページのURI",
  scope="保護リソースのアクセスに必要なスコープ群"
Cache-Control: no-store
Pragma: no-cache
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; if applicable;
適当であれば、Content-Type: application/json HTTP ヘッダーを含める。

FAPI の保護リソースエンドポイントからのレスポンスのフォーマットは、基本的には JSON であることが期待されています。

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 ヘッダーを含める。

Date ヘッダーのフォーマットは RFC 72317.1.1.1. Date/Time Formats で定義されています。例を挙げます。

Date: Sun, 06 Nov 1994 08:49:37 GMT
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;
x-fapi-interaction-id HTTP ヘッダーを応答に含める。その値は、リクエストに x-fapi-interaction-id が含まれていればそれと同じ値を、含まれていなければ UUID を生成してセットする。

これは FAPI 特有の要求事項です。FAPI に対応する保護リソースエンドポイントは、x-fapi-interaction-id HTTP ヘッダーをレスポンスに含めなければなりません。

リクエストに x-fapi-interaction-id が含まれていれば、それと同じ値をレスポンスに含めなければなりません。そうでなければ、保護リソースエンドポイントは、x-fapi-interaction-id の新しい値を生成しなければなりません。

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 特有の要求事項です。保護リソースエンドポイントのリクエスト・レスポンス仕様には何ら影響を及ぼさない要求事項ですが、クライアント側のログとサーバー側のログの付き合わせを容易にするための仕組みとして用いられます。

Part 1: 6.2.1. Protected resource provisions, 13.
shall not reject requests with a x-fapi-customer-ip-address header containing a valid IPv4 or IPv6 address.
有効な IPv4 または IPv6 アドレスを含む x-fapi-customer-ip-address ヘッダーを含むリクエストを拒否してはならない。
Part 1: 6.2.1. Protected resources provisions, 14.
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 をサポートすべき。

例えば、保護リソースエンドポイントが任意の場所にある JavaScript クライアントからのアクセスを許可したければ、Access-Control-Allow-Origin: * ヘッダーをレスポンスに含めます。

Part 1: 保護リソースアクセス時のクライアントに対する要求事項

Part 1 の『6.2.2. Client provisions』に、保護リソースアクセス時のクライアントに対する要求事項が列挙されているので、一つ一つ見ていきます。

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 アクセストークン という形式でアクセストークンを送信します。

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;
ユーザーが最後にログインした時刻を、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: 2001:DB8::1893:25c8:1946 or 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, in which case the value shall be 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

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 リファラー経由で情報が漏れないように注意。アクセストークンの有効期限は短く。
7.5 ネイティブアプリは BCP 212 に従うこと。ただし、Private-Use URI Scheme RedirectionLoopback Interface Redirection をサポートしてはならない。リダイレクト URI のスキームには Claimed https Scheme URI Redirection で紹介されている https を使うこと。
7.6 FAPI 実装および下層の OAuth/OIDC 実装の両方とも完全で正確であることが重要。OpenID Certification を参照のこと。
7.7 複数のブランドをサポートしたければ、ブランド毎に異なる issuer を用いること。

FAPI Part 2 は、リクエストオブジェクトを必須とするなどして、Part 1 で挙げられているセキュリティー上の考慮事項に対する解決策を示しています。セキュリティーリスクに対するより強固な対策が必要な際に Part 1 よりも Part 2 が推奨されます。

Part 2: Advanced

次は、Advanced セキュリティープロファイルを定める Part 2 を見ていきましょう。

Detached Signature

Part 2 の『5.1.1. ID Token as Detached Signature』は、『ID トークン』を『Detached Signature』として用いると述べています。

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

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

id_token_as_detached_signature_ja.png

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

まだ定義されていないのは state レスポンスパラメーターに対応するハッシュ値のためのクレームということで、『5.1.1. ID Token as Detached Signature』では 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 value code id_token;"(response_typecode id_token でなければならない)と要求しているのはそのためです。

しかしながら、ID2 以降、JARM を使う場合は ID トークンを Detached Signature として使う必要はありません。なぜなら、レスポンスパラメーター群の完全なセットが一つの JWT にまとめられるからです。

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

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

Part 2: 5.2.2. Authorization server, 1.
shall require a JWS signed JWT request object passed by value with the request parameter or by reference with the request_uri parameter;
request または request_uri パラメーターで署名済みリクエストオブジェクトを要求しなければならない。

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

request_object_by_value_ja.png

request_object_by_reference_ja.png

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

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

Part 2: 5.2.2. Authorization server, 2.
shall require
  1. the response_type value code id_token, or
  2. the response_type value code in conjunction with the response_mode value jwt;
  1. response_type の値として code id_token を要求するか、もしくは
  2. response_typecoderesponse_modejwt を要求しなければならない。

ID トークンを Detached Signature として用いるため、アプリケーションレイヤーで ID トークンを必要としていなくても、ID トークンの発行を要求するために id_tokenresponse_type パラメーターに含めなければなりません。

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

補足:ID2 では、JARM が使われない場合、response_typecode id_token または code id_token token のどちらか、とされていました。しかし、最終版で code id_token token は削除されました。

Part 2: 5.2.2. Authorization server, 3.
(moved to 5.2.2.1);
(5.2.2.1 へ移動)
Part 2: 5.2.2. Authorization server, 4.
(moved to 5.2.2.1);
(5.2.2.1 へ移動)
Part 2: 5.2.2. Authorization server, 5.
shall only issue sender-constrained access tokens;
発行するアクセストークンは送信者限定でなければならない。

ID2 では、この要求事項は "shall only issue authorization code, access token, and refresh token that are holder of key bound;"(HoK 対応の認可コード、アクセストークン、リフレッシュトークンのみを発行すること) でした。しかし、その要求事項は非現実的であったため、現在のものに変更されました。ご興味があれば FAPI Issue 202 の議論を参照してください。

Part 2: 5.2.2. Authorization server, 6.
shall support MTLS as mechanism for constraining the legitimate senders of access tokens;
アクセストークンの送信者を正当な者のみに制限する仕組みとして MTLS をサポートしなければならない。

ID2 では、この要求事項は "shall support [OAUTB] or [MTLS] as a holder of key mechanism;"(holder of key mechanism として Token Binding もしくは MTLS をサポートすること)というものでした。しかし、将来的に実装される見込みがないことから、OAUTB(Token Binding)は最終版から削除されました。

Part 2: 5.2.2. Authorization server, 7.
(withdrawn);
(撤回)
Part 2: 5.2.2. Authorization server, 8.
(moved to 5.2.2.1);
(5.2.2.1 へ移動)
Part 2: 5.2.2. Authorization server, 9.
(moved to 5.2.2.1);
(5.2.2.1 へ移動)
Part 2: 5.2.2. Authorization server, 10.
shall only use the parameters included in the signed request object passed via the request or request_uri parameter;
リクエストオブジェクト内のパラメーターのみを使用すること。

ID2 では、この要求事項は "shall require that all parameters are present inside the signed request object passed in the request or request_uri parameter;"(全てのパラメーターはリクエストオブジェクト内に存在しなければならない)というものでした。表現は変更されましたが、要点は同じです。FAPI Part 2 に準拠するためには、全てのパラメーターがリクエストオブジェクトに含まれていなければなりません。

これは、OIDC Core とは異なります。OIDC Core では、パラメーター群はリクエストオブジェクトの中にも外にも置くことができ、それらはマージされます。

Part 2: 5.2.2. Authorization server, 11.
may support the pushed authorization request endpoint as described in PAR;
Pushed Authorization Request エンドポイントをサポートしてもよい。

Pushed Authorization Request エンドポイント(以降 PAR エンドポイント)は OAuth 2.0 Pushed Authorization Requests (PAR) で定義されている新しいエンドポイントです。クライアントアプリケーションは、そのエンドポイントで認可リクエストを登録し、登録した認可リクエストを表すリクエスト URI を取得することができます。その後、認可エンドポイントに認可リクエストを投げる際、request_uri リクエストパラメーターの値として発行されたリクエスト URI を指定します。

図解 PAR : OAuth 2.0 Pushed Authorization Requests』から抜粋した次の図は、PAR エンドポイントを利用する認可コードフローを示しています。

par_ja.png

補足:認可リクエストを事前登録するというアイディアは ID2 の Section 7 にありました。そのセクションでは、事前登録用のエンドポイントを『リクエストオブジェクトエンドポイント』と呼んでいました。PAR 仕様はそのアイディアに基づいて策定されました。結果として、当該セクションは最終版で削除されました。

Part 2: 5.2.2. Authorization server, 12.
(withdrawn);
(撤回)
Part 2: 5.2.2. Authorization server, 13.
shall require the request object to contain an exp claim that has a lifetime of no longer than 60 minutes after the nbf claim;
リクエストオブジェクトは exp クレームを含まなければならず、nbf クレーム後の生存期間が 60 分を超えてはならない。

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

さらに、最終版で「nbf クレーム後の生存期間が 60 分を超えてはならない」という要求事項も追加されました。このため、nbf クレームも必須となりました。

クライアントアプリケーションの視点から見ると、新しい要求事項は破壊的変更です。というのは、認可リクエストのリクエストオブジェクトが nbf クレームを含んでいない場合、認可サーバーがリクエストを拒否するようになるからです。事実、公式の互換性テストスイートのいくつかのテストも、新しい要求事項のために更新が必要となりました。

認可サーバーの実装によっては、この破壊的変更の衝撃を和らげる仕組みを提供するでしょう。例えば Authlete は、認可リクエストが FAPI Part 2 リクエストと判定される場合でも nbf クレームを任意項目として処理するためのフラグ『Service.nbfOptional』を定義しました。このフラグは Service Owner コンソールの『nbf クレーム』で変更することができます。

nbf_claim_ja.png

Part 2: 5.2.2. Authorization server, 14.
shall authenticate the confidential client using one of the following methods (this overrides FAPI Security Profile 1.0 - Part 1: clause 5.2.2-4):
  1. tls_client_auth or self_signed_tls_client_auth as specified in section 2 of MTLS, or
  2. private_key_jwt as specified in section 9 of OIDC;
クライアント認証は次のどちらか(これは Part 1 の要求事項を上書き):
  1. tls_client_auth または self_signed_tls_client_auth
  2. private_key_jwt

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

クライアント認証方式 Part 1 Part 2
client_secret_basic NG NG
client_secret_post NG NG
client_secret_jwt OK NG
private_key_jwt OK OK
tls_client_auth OK OK
self_signed_tls_client_auth OK OK
Part 2: 5.2.2. Authorization server, 15.
shall require the aud claim in the request object to be, or to be an array containing, the OP's Issuer Identifier URL;
リクエストオブジェクトの aud は、認可サーバーの発行者識別子そのもの、またはそれを含む配列でなければならない。

この要求事項は最終版で追加されました。クライアントアプリケーションはリクエストオブジェクトに aud クレームを入れなければなりません。ディスカバリードキュメント内の issuer メタデータの値が認可サーバーの発行者識別子となります。(参考:OpenID Connect Discovery 1.0, 3. OpenID Provider Metadata

Part 2: 5.2.2. Authorization server, 16.
shall not support public clients;
Public クライアントをサポートしてはならない。

この要求事項は最終版で追加されましたが、以前の FAPI バージョンの時点で FAPI 2 の文脈で Public クライアントをサポートすることは論理的に不可能だったと言われています。

Part 2: 5.2.2. Authorization server, 17.
shall require the request object to contain an nbf claim that is no longer than 60 minutes in the past; and
リクエストオブジェクトは nbf クレームを含まなければならず、それは 60 分を超える過去をさしていてはいけない。

13 番目の規定で nbf クレームが必須であることが示唆されていましたが、この 17 番目の規定でそれが明確に述べられています。

Part 2: 5.2.2. Authorization server, 18.
shall require PAR requests, if supported, to use PKCE (RFC7636) with S256 as the code challenge method.
PAR リクエストでは、コードチャレンジメソッドを S256 とする PKCE の使用を要求しなければならない。

ここで PAR は OAuth 2.0 Pushed Authorization Requests のことです。

FAPI の以前のバージョンでは、Part 2 の分脈において PKCE が要求されるのは「クライアントタイプが PUBLIC の場合のみ」でした。しかしこの要求事項は最終版で「PAR が使用された場合のみ」と変更されました。

Part 2: 5.2.2.1. ID Token as detached signature
In addition, if the response_type value code id_token is used, the authorization server.
加えて、response_typecode id_token の場合、認可サーバーは

Section 5.2.2.1 は ID トークンが Detached Signature として使用された場合の追加要求事項を列挙しています。

Part 2: 5.2.2.1. ID Token as detached signature, 1.
shall support OIDC;
OIDC をサポートしなければならない。
Part 2: 5.2.2.1. ID Token as detached signature, 2.
shall support signed ID Tokens;
署名された ID トークンをサポートしなければならない。
Part 2: 5.2.2.1. ID Token as detached signature, 3.
should support signed and encrypted ID Tokens;
署名され、かつ暗号化された ID トークンをサポートすべきである。

OIDC の観点からは、これらの要求事項は新しいものではありません。定義上、ID トークンは常に署名されています。ID トークンの暗号化サポートは任意です。

Part 2: 5.2.2.1. ID Token as detached signature, 4.
shall return ID Token as a detached signature to the authorization response;
Detached Signature として ID トークンを発行しなければならない。

ID トークンを発行しなければならないと書かれていますが、Section 5.2.2.1 の冒頭に書かれている条件により response_typeid_token が含まれているので、必然的に ID トークンが発行されます。そのため、本規定は存在する必要はありません。

Part 2: 5.2.2.1. ID Token as detached signature, 5.
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; and
ID トークンに s_hash を含めなければならない。ただし、認可エンドポイントから発行された ID トークンに s_hash が含まれていれば、トークンエンドポイントから発行される ID トークンの s_hash は省略可能。

JARM が使われている場合は、この規定に従う必要はありません。

Part 2: 5.2.2.1. ID Token as detached signature, 6.
should not return sensitive PII in the ID Token in the authorization response, but if it needs to, then it should encrypt the ID Token.
認可レスポンス内の ID トークンに重要な PII を入れるべきではないが、その必要がある場合は ID トークンを暗号化すべき。

PII は "Personally Identifiable Information" の略で、「個人を特定することが可能な情報」を意味します。

ID トークン暗号化の機能は OIDC Core の時から存在します。ID トークンの暗号化アルゴリズムが非対称型である場合、認可サーバーはクライアントアプリケーションの公開鍵を自身のデータベースで直接管理するか、もしくはクライアントの jwks_uri メタデータが指す場所から JWK Set ドキュメントをフェッチして、そのドキュメントから公開鍵を取り出さなければなりません。

ID トークンを署名する際は、認可サーバーが取り扱わなければならないのはサーバー側の鍵だけです。

id_token_signing_ja.png

一方、ID トークン暗号化をサポートするためには、認可サーバーはクライアント側の鍵も取り扱わなければなりません。

id_token_encryption_ja.png

これが、ID トークンの暗号化をサポートしている認可サーバーの実装が少ない理由です。

Part 2: 5.2.2.2. JARM
In addition, if the response_type value code is used in conjunction with the response_mode value jwt, the authorization server
加えて、response_type=coderesponse_mode=jwt と併せて使用された場合、認可サーバーは:
Part 2: 5.2.2.2. JARM, 1.
shall create JWT-secured authorization responses as specified in JARM, Section 4.3.
JARM 仕様 Section 4.3 で示されている通りに JWT で保護された認可レスポンスを生成しなければならない。

この規定は FAPI 固有の要求事項ではありません。単に、JARM 実装は JARM 仕様が定めているように動作すべきと言っているに過ぎません。

response_typeid_token を含んでいない場合、認可レスポンスは ID トークンを含みません。そのため、ID トークンを Detached Signature として用いることはできません。この場合、認可レスポンスが改ざんされていないことを保証するため、JARM を使わなければなりません。

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

FAPI 最終版で、Part 2 の Section 5.2.3 のタイトルは「Public client」から「Confidential client」へと変更されました。

Part 2: 5.2.3. Confidential client, 1.
shall support MTLS as mechanism for sender-constrained access tokens;
送信者限定アクセストークンの仕組みとして MTLS をサポートしなければならない。

つまり、認可サーバーは RFC 8705Section 3 で定義されている『証明書に紐付いたアクセストークン』を発行しなければなりません。

Part 2: 5.2.3. Confidential client, 2.
shall include the request or request_uri parameter as defined in Section 6 of OIDC in the authentication request;
認証リクエストに request または request_uri を含めなければならない。

認可サーバーに対する要求事項にも挙げられているように、request パラメーターもしくは request_uri パラメーターが含まれていなければなりません。OIDC Core は "If one of these parameters is used, the other MUST NOT be used in the same request."(どちらか一方のパラメーターしか使ってはならない)と言っている点には注意してください。

Part 2: 5.2.3. Confidential client, 3.
shall ensure the Authorization Server has authenticated the user to an appropriate Level of Assurance for the client's intended purpose;
適切な LoA でユーザー認証をおこなわなければならない。

この規定は単に、ユーザー認証を適切に行わなければならないと言っているに過ぎません。過去にこの規定内に含まれていた "by requesting the acr claim as an essential claim"(acr クレームを必須クレームとして要求することにより)という文言は FAPI 最終版で削除されました。

~~~ 歴史 ~~~

ID2 では、この規定は "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 クレームを必須として要求することにより行う)というものでした。

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』ページにリストされました。

authlete_listed_in_open_banking_security_profile_conformance.png

この話については、動画『OAuth & OIDC 勉強会 認可リクエスト編 by #authlete​ - 7. ユーザーの識別・認証』の 14 分 36 秒あたりから話していますので、ご興味があればご覧ください。

~~~ 歴史振り返り終わり ~~~

せっかく OPEN_BANKING フラグを用意したものの、"by requesting the acr claim as an essential claim" という文言が FAPI 最終版で削除されたため、Authlete は ACR が必須クレームとして要求されているかどうかをチェックすることをやめました。そのため、OPEN_BANKING フラグは今となっては意味がなくなってしまいました。

Part 2: 5.2.3. Confidential client, 4.
(moved to 5.2.3.1);
(5.2.3.1 に移動)
Part 2: 5.2.3. Confidential client, 5.
(withdrawn);
(撤回)
Part 2: 5.2.3. Confidential client, 6.
(withdrawn);
(撤回)
Part 2: 5.2.3. Confidential client, 7.
(moved to 5.2.3.1);
(5.2.3.1 に移動)
Part 2: 5.2.3. Confidential client, 8.
shall send all parameters inside the authorization request's signed request object
リクエストオブジェクト内に全てのパラメーターを入れること。
Part 2: 5.2.3. Confidential client, 9.
shall additionally send duplicates of the response_type, client_id, and scope parameters/values using the OAuth 2.0 request syntax as required by Section 6.1 of the OpenID Connect specification if not using PAR;
PAR が使われていなければ、OAuth 仕様に適合するように、response_typeclient_idscope を重複して送らなければならない。

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

FAPI 最終版では、"if not using PAR"(PAR が使われていなければ)という条件を追加しました。これは、逆に言うと、PAR が使われていればリクエストパラメーター群は OAuth 2.0 / OIDC に準拠する必要はないということを示唆しています。この非互換性は JWT Secured Authorization Request (JAR) から来ています。詳細は『JAR (JWT Secured Authorization Request) に関する実装者の覚書』をご参照ください。

Part 2: 5.2.3. Confidential client, 10.
shall send the aud claim in the request object as the OP's Issuer Identifier URL;
リクエストオブジェクトに aud クレームが必須。値は認可サーバーの発行者識別子。
Part 2: 5.2.3. Confidential client, 11.
shall send the exp claim in the request object that has a lifetime of no longer than 60 minutes;
リクエストオブジェクトに exp クレームが必須。リクエストオブジェクトの生存期間は 60 分を超えてはならない。

上記二つの規定については、同様のものが Section 5.2.2 にもあります。

Part 2: 5.2.3. Confidential client, 12.
(moved to 5.2.3.1);
(5.2.3.1 へ移動)
Part 2: 5.2.3. Confidential client, 13.
(moved to 5.2.3.1);
(5.2.3.1 へ移動)
Part 2: 5.2.3. Confidential client, 14.
shall send a nbf claim in the request object;
リクエストオブジェクトに nbf クレームが必須。

この規定についても Section 5.2.2 に同じものがあります。

Part 2: 5.2.3. Confidential client, 15.
shall use RFC7636 with S256 as the code challenge method if using PAR; and
PAR を使用している場合、コードチャレンジメソッドを S256 とし、RFC 7636 を使わなければならない。

つまり、PAR を使用している場合、認可リクエストは code_challenge_method=S256 を含まなければなりません。

Part 2: 5.2.3. Confidential client, 16.
shall additionally send a duplicate of the client_id parameter/value using the OAuth 2.0 request syntax to the authorization endpoint, as required by Section 5 of JAR, if using PAR.
PAR を使用している場合、JAR の Section 5 に従い、client_id を重複して送らなければならない。

PAR 仕様は、リクエストオブジェクトを JAR の規則に則って処理することを要求しています。JAR 仕様は response_type を任意パラメーター扱いにすることにしましたが、client_id は必須のままとしています。詳細は『JAR (JWT Secured Authorization Request) に関する実装者の覚書』をご参照ください。

Part 2: 5.2.3.1. ID Token as detached signature
In addition, if the response_type value code id_token is used, the client
加えて、response_typecode id_token であれば、クライアントは:

Section 5.2.3.1 は、ID トークンを Detached Signature として使用する際のクライアントに対する要求事項を列挙しています。

Part 2: 5.2.3.1. ID Token as detached signature, 1.
shall include the value openid into the scope parameter in order to activate OIDC support;
scope パラメーターに openid を含めなければならない。

これは FAPI 固有の要求事項ではありません。OIDC Core は、OIDC リクエストは scope パラメーターに openid を含まなければならないと定めています。詳細については、OIDC Core の Section 3.1.2.1 に書かれている scope パラメーターの説明を参照してください。

Part 2: 5.2.3.1. ID Token as detached signature, 2.
shall require JWS signed ID Token be returned from endpoints;
各エンドポイントから署名された ID トークンを返さなければならない。

OIDC の観点からは何も新しいことはありません。定義上、ID トークンは常に署名されます。また、response_typecode id_tokenscopeopenid を含む場合、認可エンドポイントとトークンエンドポイントの双方とも ID トークンを返します。これらのエンドポイント群から何が返されるかについては、『OpenID Connect 全フロー解説』をご参照ください。

code_id_token_ja.png

Part 2: 5.2.3.1. ID Token as detached signature, 3.
shall verify that the authorization response was not tampered using ID Token as the detached signature;
ID トークンを Detached Signature として使用し、認可レスポンスが改ざんされていないことを検証しなければならない。

つまり、クライアントアプリケーションは、ID トークン外にあるレスポンスパラメーター群のハッシュ値を計算し、それらを ID トークン内のハッシュ値群と比較しなければなりません。

Part 2: 5.2.3.1. ID Token as detached signature, 4.
shall verify that s_hash value is equal to the value calculated from the state value in the authorization response in addition to all the requirements in 3.3.2.12 of OIDC; and
NOTE: This enables the client to verify that the authorization response was not tampered with, using the ID Token as a detached signature.
state を元に計算した値と s_hash の値が一致することを検証しなければならない。

この規定では states_hash の組について特別に言及していますが、他にもパラメーターとハッシュ値の組み合わせがあることは既出の通りです。

Part 2: 5.2.3.1. ID Token as detached signature, 5.
shall support both signed and signed & encrypted ID Tokens.
署名された ID トークンおよび、署名・暗号化された ID トークンの双方をサポートしなければならない。

定義上、ID トークンは常に署名されます。ID トークンが暗号化される場合、署名と暗号化の順番は、「署名してから暗号化」です。結果として、暗号化された ID トークンは下図が示すような「Nested JWT」になります。

nested_jwt_ja.png

ID トークンの構造の詳細については、『IDトークンが分かれば OpenID Connect が分かる』をご参照ください。

Part 2: 5.2.3.2. JARM
In addition, if the response_type value code is used in conjunction with the response_mode value jwt, the client
加えて、response_type=coderesponse_mode=jwt と併せて使用された場合、クライアントは:
Part 2: 5.2.3.2. JARM, 1.
shall verify the authorization responses as specified in JARM, Section 4.4.
JARM 仕様で定められている通りに認可レスポンスを検証しなければならない。

検証手順の詳細については JARM の Section 4.4. Processing rules を参照してください。

Part 2: 5.2.4.
(withdrawn)
(撤回)
Part 2: 5.2.5.
(withdrawn)
(撤回)
Part 2: 6.2.1. Protected resource provisions, 1.
shall support the provisions specified in clause 6.2.1 Financial-grade API Security Profile 1.0 - Part 1: Baseline; and
Part 1 の 6.2.1 の規定群をサポートしなければならない。
Part 2: 6.2.1. Protected resource provisions, 2.
shall adhere to the requirements in MTLS.
MTLS の要求事項に従わなければならない。
Part 2: 6.2.2. Client provisions
The client supporting this document shall support the provisions specified in clause 6.2.2 of Financial-grade API Security Profile 1.0 - Part 1: Baseline.
Part 1 の 6.2.2 の規定群をサポートしなければならない。

簡単に言うと、Part 2 の Section 6 は、保護リソースエンドポイントとクライアントアプリケーションが証明書に紐付くアクセストークンを使うこと、および、Part 1 の規定群に従うことを要求しています。

Part 2: 7. (Withdrawn)
(撤回)

ID 2 の Section 7 は「リクエストオブジェクトエンドポイント」でした。しかし、リクエストオブジェクトエンドポイントは、"OAuth 2.0 Pushed Authorization Requests" (PAR) で定義されている Pushed Authorization Request エンドポイントで置き換えられたため、当セクションは FAPI 最終版で削除されました。PAR の概要については、『図解 PAR : OAuth 2.0 Pushed Authorization Requests』をご参照ください。

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

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

要約
8.1 本仕様は RFC 6749Section 10 および RFC 6819 にあるセキュリティー上の考慮事項を参照する。
8.2 保護リソースエンドポイントは証明書に紐付くアクセストークンのみを受け入れること。
8.3.1 クライアントは認可サーバー毎に異なるリダイレクト URI を用いるべきである。
8.3.2 攻撃者により偽のトークンエンドポイントを信じこまされると、認可コードとクライアントシークレットを攻撃者に渡してしまう。
8.3.3 IdP mix-up 攻撃への対策としてハイブリッドフローを用いることができる。
8.3.4 (削除)
8.3.5 FAPI Part 2 では、アクセストークンは X.509 証明書に紐付くので、対応する証明書がなければ、盗まれても利用できない。
8.4.1 RFC 6749 では認可リクエスト・レスポンスの完全性(integrity)は保証しない。
8.4.2 リクエストオブジェクトを利用することで、認可リクエストの改竄を防ぐことができる。
8.4.3 ハイブリッドフローまたは JARM を利用することで、認可レスポンスの改竄を防ぐことができる。
8.5 TLS 1.2 で用いる暗号スイートに制限がかかる。

Part 2 の『8.5. TLS considerations』により、TLS のバージョンが 1.3 未満の場合、許容される暗号スイートは次の 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 で許可されている暗号スイートを追加で許容してもかまいません。

......個人的に次の暗号スイート群を除外する理由を見つけられなかったので、

  • TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
  • TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384

Issue 216 TLS_ECDHE_ECDSA cipher suites を作成し、これらを追加するように提案しました。1 年と 4 ヶ月後、FAPI で TLS 1.3 を許可することになったとの理由で、当 Issue はクローズされました。

要約
8.6 JWS の署名アルゴリズムとして許されるのは PS256ES256 のみ。

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

ちなみに、認可サーバーは次の箇所で JWS を使っています。

仕様 用途
1 RFC 7523 client_assertion パラメーター
2 OIDC Core ID トークン
3 OIDC Core リクエストオブジェクト
4 OIDC Core UserInfo エンドポイントからのレスポンス
5 JARM レスポンス JWT
6 CIBA Core バックチャネル認証リクエスト

fapi_part2_8_6_ja.png

要約
8.6.1 暗号アルゴリズム RSA1_5 は使用禁止。

暗号アルゴリズムに関するこの規定は FAPI 最終版で追加されました。FAPI Part 2 では RSA1_5 の使用が禁じられます。このアルゴリズム識別子は RFC 75184.1. "alg" (Algorithm) Header Parameter Values for JWE で定義されていて、RSAES-PKCS1-v1_5 を表しています。

要約
8.7 認定を受けた FAPI 実装を使用すること。
8.8 アクセストークン無しで特権アクションを許可してはならない。
8.9 署名検証用の鍵は jwks_uri/jwks クライアントメタデータ(RFC 7591)や jwks_uri サーバーメタデータ(RFC 8414)を介してアクセス可能でなければならない。
8.10 同じ鍵を共有するクライアントの一つでもその防御が突破されると、全てのクライアントの防御が突破される結果となる。
8.11 JWK Set は同じ kid を持つ鍵を複数含むべきではないが、その場合でも、鍵の他の属性を利用して鍵を絞り込んでもよい。

FAPI 実装

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

Baseline と Advanced の区別

クライアントアプリケーションがアクセストークンを要求したり、そのアクセストークンを使って API にアクセスしてきたとき、FAPI Part 1 と FAPI Part 2 のどちらのセキュリティプロファイルを適用すべきでしょうか?

固定的に設定をおこなう実装もあれば、その判断を実行時に動的におこなう実装もあることでしょう。FAPI 仕様は、どちらのセキュリティプロファイルを適用すべきかを判断する方法について何も述べていません。

単純な解決手段は「全ての認可リクエストを FAPI Part 2 リクエストとみなす」というものになるでしょう。実は英国オープンバンキングはそうなっています。このような決め打ちの実装は、単発のシステム開発であれば許容できるかもしれません。

しかしながら、汎用的な認可サーバー実装では、適用するセキュリティプロファイルをどちらかに(またはそれ以外)に固定するのは賢明とは言えません。なぜなら、あまりにシステム設計の柔軟さを損ねてしまうからです。そのため、汎用ソリューションの場合、認可リクエストが FAPI Part 1、FAPI Part 2、またはその以外かどうかは、動的に判断するように実装したほうが好ましいと言えます。

では、どうやって動的に判断すればよいでしょうか? これを考えていくと行き着く方法は一つで要求されているスコープを見て判断することになります。

※:RFC 8707 Resource Indicators for OAuth 2.0 で定義されている resource リクエストパラメーターを利用する方法もありうるかもしれません。

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

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

Authlete はまず、スコープに任意の属性群を紐づけるための汎用的な仕組みを実装しました。その後、属性名 fapi を特別扱いし、その値が r であれば FAPI Part 1、rw であれば FAPI Part 2 と判断するようにしましたた。

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 Part 1、fapi=rw は含まれていないが fapi=r が一つ以上含まれていれば FAPI Part 2 とみなします。

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

補足:ID2 では、FAPI Part 1 と FAPI Part 2 は「Read-Only Security Profile」、「Read and Write Security Profile」という名称でした。FAPI 最終版で、これらの名前は「Baseline Security Profile」、「Advanced Security Profile」へと変更されました。fapi 属性用の rrw という値は、古い名称に由来しています。

Mutual TLS

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

  1. クライアント証明書の提示を伴う TLS 通信
  2. クライアント証明書を用いるクライアント認証
  3. Certificate Binding

1 は、API 管理ソリューションが扱う部分です。しかし、2 と 3 については、必ずしも API 管理レイヤーで扱う必要はありません。むしろ、良いシステムアーキテクチャであれば、API 管理層からは独立した別の層で扱うでしょう。

Authlete は、その独特なアーキテクチャーにより、API 管理レイヤーの仕事は一切おこないません。つまり、1 のレイヤーには全く関与しません。一方で、2 と 3 の機能をサポートします。これにより、Authlete を使えば、好きな API 管理ソリューションを使いつつ FAPI で要求される MTLS をサポートすることができます。実際に私は Amazon API Gateway 上で MTLS を試し、その手順を説明する『金融グレード Amazon API Gateway』という記事を書きました。

certificate-binding-components_ja.png
Amazon API Gateway 上で MTLS を実現する際のコンポーネント配置の例

どんな API 管理ソリューションだとしても、TLS 通信で使われたクライアント証明書を取り出す機能さえ提供していれば、Authlete と組み合わせて使うことで、FAPI の MTLS をサポートすることができます。

API 管理ソリューションが直接 2 と 3 の機能を実装しようとするかもしれません。しかし、実装完了までには時間がかかるでしょうし、そもそも、当該機能を API 管理レイヤーで直接サポートするのは良い設計とは言えません。現時点では、大手クラウドベンダーの 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 徹底入門』というタイトルで翔泳社から販売されています。監修は Authlete 社です。

OAuth_2_in_Action-Cover.jpeg OAuth徹底入門-Cover.png
OAuth 2 in Action OAuth 徹底入門

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

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 という属性名でリフレッシュトークンの有効期限も設定することができます。

補足:Authlete 2.1 以降では、クライアント単位でアクセストークン有効期限を設定することもできます。詳細は Authlete ナレッジベースの『トークンの有効期間の計算ロジック』をご参照ください。

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

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

この機能は、「アクセストークンの有効期限」で紹介したスコープ単位の属性では実現できません。というのは、スコープ単位ではなく、アクセストークン単位で個別に情報を紐付ける必要があるからです。

Authlete には、任意のキー・バリューの組をアクセストークンに紐づける仕組みが昔から存在しています。この機能を利用することで、取引情報をアクセストークンに紐づけることができます。この機能の詳細は『Extra Properties』で説明されています。また、Authlete ナレッジベースの『トークンに任意のプロパティをひもづける方法』もご参照ください。

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

認可詳細

バージョン 2.2 以降、Authlete は OAuth 2.0 Rich Authorization RequestsRAR)をサポートしています。この標準仕様は authorization_details パラメーターを追加します。

authorization_details パラメーターは、認可の詳細情報をアクセストークンに保持させる目的で使用することができます。例えば、「いくら?」「誰に?」といった支払いに関する詳細情報です。

仕様によれば、authorization_details パラメーターは、scope パラメーターが使われる場所であればどこでも使うことができます。例えば、認可リクエスト、トークンレスポンス、イントロスペクションレスポンス、などで使用可能です。

authorization_details_in_authorization_request.png
認可リクエスト内の authorization_details
authorization_details_in_token_response.png
トークンレスポンス内の authorization_details
authorization_details_in_introspection_response.png
イントロスペクションレスポンス内の authorization_details

RAR は、認可の詳細を記述し、その情報をアクセストークンに紐付ける機能を提供するオープン標準仕様です。RAR は FAPI 2.0 の技術要素の一つとして採用されることになっています(FAPI FAQ の "Are there FAPI 2.0 implementations?" を参照のこと)。

Authlete の Extra Properties も同じ目的で使用することができます。機能的な違いを一つ挙げるとすれば、Extra Properties では各プロパティーを公開するか隠しておくかを選ぶことができます。隠されたプロパティー群は OAuth/OIDC のレスポンス内に現れることはなくなりますが、Authlete のイントロスペクション API(/auth/introspection API)で取り出すことができます。アクセストークンに情報を紐付けたいが、その情報をクライアントアプリケーションやユーザーには見せたくないというケースはあります。そのようなとき、Extra Properties が便利です。

おわりに

長い記事を最後まで読んでいただき、ありがとうございました。

Authlete は FAPI 1.0 最終版および FAPI 2.0 で採用予定の既知の技術仕様を実装済みです。Authlete アカウント(登録)があれば、Authlete API チュートリアルを参照しながら FAPI を試すことができます。

認定 FAPI 実装にご興味があれば、Authlete 社までお問い合わせください。

236
228
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
236
228