MS_JARM - NetDevInfraWGinOSSConsortium/NetDevInfraWiki GitHub Wiki

JWT Secured Authorization Response Mode for OAuth 2.0 (JARM)

概要

  • ドイツの金融業界の要望に対応するため、驚くほどのスピードで策定され、
    駆け込みで FAPI Implementer's Draft 第二版と一緒に処理された。

  • FAPI Part 2では、分離トークン(s_hash)の代替手段だと
    書かれている。

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

※ よくよく見ると、JWT Secured Authorization Request (JAR)(リクエスト)の
レスポンス版である。

補足(何を解決するのか): FAPIが指摘した
認可レスポンスはブラウザ経由なので無防備」という問題への回答である。

方式 保護の仕方
s_hashFAPI Part 2 id_token の中にハッシュを入れ、Client が突合
JARM レスポンス全体を 1 つの JWS にまとめて署名

s_hash 方式は id_token が必須(= OIDC 前提)だが、
JARM は素の OAuth 2.0 でも使えるという利点がある。
また、署名だけでなく JWE による暗号化も選べる。

詳細

  • Authorization Response に JWTを使う方法が定義されている。
  • Response Type,
    Response Mode により、
    挙動と JWT の中身が違ってくる。
  • JWT の alg などは仕様範囲外なので、よく考えて設計する必要がある。

Discovery / Registration

  • Discovery
    response_modes_supported パラメタで response_mode
    AuthZ metadata をアドバタイズ
  • Registration
    Client metadata を登録

Metadata

Client metadata

Client が、JWT の署名・暗号にどのアルゴリズムを使用して欲しいかを指定。

  • authorization_signed_response_alg
  • authorization_encrypted_response_alg
  • authorization_encrypted_response_enc

AuthZ metadata

Authorization Server がサポートする JWT の署名・暗号アルゴリズムを列挙。

  • authorization_signing_alg_values_supported
  • authorization_encryption_alg_values_supported
  • authorization_encryption_enc_values_supported

response_mode

返し方
query.jwt Location: https://client.com/callback?response={JWT}
fragment.jwt Location: https://client.example.com/cb#response={JWT}
form_post.jwt 200 OK + 自動 POST する HTML(<input name="response" value="{JWT}">
jwt ショートカット。response_type=code なら query.jwttoken なら fragment.jwt

補足(query.jwt が使える理由): Multiple Response Typeでは
「トークンを Query String に載せてはならない」とされていたが、
JARM では token でも query.jwt が使える

理由は、JWT が署名(さらに任意で暗号化)されているためである。
JWE で暗号化すれば、URL に載っても中身は読めない。
「無防備な生パラメタ」が「保護されたひとかたまり」に変わることで、
載せる場所の制約が緩む、という構図になっている。

response_type ごとのペイロード

上記の {JWT} には、以下のペイロードを署名して JWS 化したものを入れる。

code の場合

{
  "iss": "https://accounts.example.com",
  "aud": "s6BhdRkqt3",
  "exp": 1311281970,
  "code": "PyyFaux2o7Q0YfXBU32jhw.5FXSQpvr8akv9CeRDSd0QA",
  "state": "S8NJ7uqk5fY4EjNvP_G_FtyJu6pUsvH9jsYni9dMAJw"
}

token の場合

{
  "iss": "https://accounts.example.com",
  "aud": "s6BhdRkqt3",
  "exp": 1311281970,
  "access_token": "2YotnFZFEjr1zCsicMWpAA",
  "state": "S8NJ7uqk5fY4EjNvP_G_FtyJu6pUsvH9jsYni9dMAJw",
  "token_type": "bearer",
  "expires_in": "3600",
  "scope": "example"
}

エラーの場合

{
  "error": "access_denied",
  "state": "S8NJ7uqk5fY4EjNvP_G_FtyJu6pUsvH9jsYni9dMAJw"
}

補足(iss が入っているのが効く): ペイロードに iss(発行者)
含まれる点は見落とされやすいが重要である。
これにより Client は
「どの Authorization Server から返ってきたレスポンスか」を検証できる

FAPIで述べた IdP Mix-Up 攻撃
(複数 AS を扱う Client が、どの AS から返ったか判別できない問題)への
直接的な対策になっている。
後に RFC 9207(認可レスポンスに iss を含める)として
一般化された考え方でもある。

実装に関する考察。

ベースライン

  • 一般的に code 系と token 系でエンドポイントが分かれている。
  • querypost の共通化は
    (MVC を使用している場合、バインダ機能により)容易のハズ。
  • fragment については、サーバで処理できないので
    Redirect エンドポイントではスルーすれば良い(実装不要)。

code (authorization code)

対応
query query(既定) そのまま
query query.jwt 検証・デコード処理を追加
fragment fragment SPA で PKCE を使用する際に必要
fragment fragment.jwt 同上(jwt でセキュリティ強化)
form_post form_post Forms から取得(メジャーなユースケース)
form_post form_post.jwt Forms から検証・デコード

token (Implicit, Hybrid)

対応
fragment fragment(既定) そのまま
fragment fragment.jwt 検証・デコード処理を追加
form_post form_post Forms から取得し、Hidden に入れる
form_post form_post.jwt Forms から検証・デコードし、Hidden に入れる
query 系 実装不要(fragment → query は NG。JWE 化していれば OK らしいが…)

移行メモ(正誤): 表の元記述にあった「fragmen」は
fragment の脱字である。

補足(現在の位置づけ): JARM は
FAPI 1.0 Advanced(Part 2)の選択肢の一つとして標準化されたが、
FAPI 2.0 では採用されていない

FAPI 1.0 FAPI 2.0
認可レスポンスの保護 s_hash または JARM 不要(PAR + PKCE で担保)

FAPI 2.0 は「認可リクエストをブラウザに通さない(PAR)」
code を PKCE で縛る」ことで、
そもそもレスポンスを改ざんしても意味が無い状態を作った。
追加の署名で守るより、攻撃面自体を消す方向に進んだ形である。

既存の FAPI 1.0 準拠システムでは現役の仕様なので、
実装の理解としては引き続き必要になる。

参考

関連仕様


Tags: 移行, IT国際標準, 認証基盤, クレームベース認証, OAuth

⚠️ **GitHub.com Fallback** ⚠️