※当サイトの記事には、広告・プロモーションが含まれます。

OpenID Connectは必須らしい、何故ならOAuth 2.0が本来の意図を無視されて利用されてきた故らしい

nazology.net

⇧ amazing...

OpenID Connectは必須らしい、何故ならOAuth 2.0が本来の意図を無視されて利用されてきた故らしい

何やら、

zenn.dev

www.sakimura.org

OAuth は Authorization Delegation Protocol = 認可をデリゲーションするためのプロトコルであって、ユーザ認証のためのプロトコルではないからです

単なる OAuth 2.0 を認証に使うと、車が通れるほどのどでかいセキュリティー・ホールができる – @_Nat Zone

問題の原因は、access_token の audience は resource endpoint であるのに対して、認証に使うトークンの audience は client でなければいけないというところにあります。だから、OpenID Connect では、client を audience にした id_token という、access_token とは別のトークンを発行しているのです。Facebook の signed_request も同じです。

単なる OAuth 2.0 を認証に使うと、車が通れるほどのどでかいセキュリティー・ホールができる – @_Nat Zone

ちゃんと治してくださいね、皆さん。治すってことは、OpenID Connect 対応するってことですよ!

単なる OAuth 2.0 を認証に使うと、車が通れるほどのどでかいセキュリティー・ホールができる – @_Nat Zone

⇧ということらしく、そもそも、OAuth 2.0が「認可」の機能を目的とした仕様であり、「認証」用途を意図していないらしいという衝撃...

まじか...

一番重要な「認証」「認可」の内、「認証」周りの仕様については定義されていないってことか...

何てこった...

それにしても、参考サイト様、駄目だしについてはシーケンス図で詳細に説明してくれているのですが、肝心の対策についてはシーケンス図も無いし詳細な説明してれてくれていない...

2024年3月17日(日)追記:↓ ここから

ちなみに、

qiita.com

余談ですが、以前崎村さんにお会いしたときに「OpenID Connect の仕様の複雑さに発狂しそうになりました」とお伝えしたところ、「それでも(過去の関連仕様と比べて)だいぶ簡単にしたんですけどね」というような感じのお返事をもらいました。そのときに思ったのは、「あの仕様を簡単と言うとは、この方はどれだけ頭いいんだ・・・」でした。OpenID Connect のサイトには、OpenID Connect のことを「simple identity layer」と紹介していて、おそらく OpenID Foundation の頭のいい方々は嘘偽りなく simple だと思っているのでしょうが、良い意味であまり真に受けず、OpenID Connect にはしっかりした体制で取り組むことをお勧めします。

OAuth 2.0 + OpenID Connect のフルスクラッチ実装者が知見を語る #OAuth - Qiita

⇧ とあって、自分も「OpenID Connect」の仕様、分かり辛いと思っていたので(と言うか、後述の「Authlete」さんの整理されたシーケンス図を見て、漸くイメージが付いた感じ)、「OpenID Connect」の内部資料みたいなのがあるような気がしていて、内輪だけで共有してる部分が絶対にありそう。

そもそも、「OAuth 2.0」と「OpenID Connect」の登場人物の対応が、「OpenID Connect」の仕様からだと読み取れないので。

2024年3月17日(日)追記:↑ ここまで

OAuth 2.0 の仕様を定義してるらしい「RFC 6749」を確認してみる

ということで、「RFC 6749」の概要を確認してみたところ、

openid-foundation-japan.github.io

Abstract

OAuth 2.0 は, サードパーティーアプリケーションによるHTTPサービスへの限定的なアクセスを可能にする認可フレームワークである. サードパーティーアプリケーションによるアクセス権の取得には, リソースオーナーとHTTPサービスの間で同意のためのインタラクションを伴う場合もあるが, サードパーティーアプリケーション自身が自らの権限においてアクセスを許可する場合もある. 本仕様書はRFC 5849に記載されているOAuth 1.0 プロトコルを廃止し, その代替となるものである.

https://openid-foundation-japan.github.io/rfc6749.ja.html

⇧ Oh, my gosh...

確かに、

OAuth 2.0 は, サードパーティーアプリケーションによるHTTPサービスへの限定的なアクセスを可能にする認可フレームワークである.

とあり、「認可」としか説明されておらず、「認証」という言葉が出て来ていない...

ちょっと前に、

ts0818.hatenablog.com

⇧ 上記の記事でまとめていたのだけど、「OAuth 2.0」だけだと脆弱性のリスクを排除した「認証」は成立しないってことみたいですな。

つまり、脆弱性のリスクを排除した「認証」を実現するためには、

 \mathsf{OAuth } \ \mathsf{ 2.0} + \mathsf{ \Large{α} }

である必要があり、 \mathsf{ \Large{α} } としては、今のところ、「OpenID Connect」の仕組みが有効な手立てであるということのよう。

ちなみに、脆弱性のリスクのあると言われている「implicit grant flow」のフローは、

⇧ 上図のような感じらしい。

で、肝心の対策ができている版のフローの全体像は載せてくれていないという...

OpenID Connect Core 1.0 incorporating errata set 2」を確認してみる

OpenID Connect」については、RFC(Request for Comments)とか無いらしいのだけど、

openid.net

Abstract

OpenID Connect 1.0 is a simple identity layer on top of the OAuth 2.0 protocol. It enables Clients to verify the identity of the End-User based on the authentication performed by an Authorization Server, as well as to obtain basic profile information about the End-User in an interoperable and REST-like manner.

https://openid.net/specs/openid-connect-core-1_0.html

⇧ ということで、「OAuth 2.0」だと不可能だった脆弱性のリスクを排除した「ユーザー認証」の機能についてを補完するのが「OpenID Connect」ということらしい。

OpenID Connect」の全体の概要はというと、

1.3. Overview

The OpenID Connect protocol, in abstract, follows the following steps.

  1. The RP (Client) sends a request to the OpenID Provider (OP).
  2. The OP authenticates the End-User and obtains authorization.
  3. The OP responds with an ID Token and usually an Access Token.
  4. The RP can send a request with the Access Token to the UserInfo Endpoint.
  5. The UserInfo Endpoint returns Claims about the End-User.

https://openid.net/specs/openid-connect-core-1_0.html

These steps are illustrated in the following diagram:

https://openid.net/specs/openid-connect-core-1_0.html

⇧ 上記のようなフローになるらしい。

う~む、「OAuth 2.0」のどの部分に組み込めば良いのか全く分からん...

整理すると

ここまでの情報を整理してみると、「OpenID Connect」ないしは、それに類似する機能を実現していないと「認証」において脆弱性のリスクを排除できていない致命的なアプリケーションになってしまうことになると。

何と言うか、かなり深刻な問題と言う気がするのと、2012年頃から議論されていた問題であるのにも関わらず、未だに実装例が欠しいのが哀しいところですな...

そもそも、

 \mathsf{OAuth } \ \mathsf{ 2.0} + \mathsf{ \Large{α} }

を実現するにあたって、シーケンス図と登場人物、実装すべき機能の対応が簡潔に説明できているドキュメントが無いものな...

未だに情報が整理されていないってことなんかね。

今のところ、「Authlete」さんの説明がイメージし易いと思われるのですが、

www.authlete.com

これは典型的に、認可コードグラントフロー、リダイレクトベースのフローのケースですけれども、この場合にはまず、 …このあたり説明しなくても、もしかしてもういいですかね。

認可リクエストが飛んできて、ユーザー認証と同意があって、認可コードがまたブラウザ経由で渡されて、ここからブラウザリダイレクトで得た認可コードを、 サーバートゥサーバーでアクセストークンに引き換えます。そしてもらったアクセストークンを使って API にアクセスする、というような流れです。

https://www.authlete.com/ja/resources/videos/20200131/01/

⇧ 上記のような「OAuth 2.0」の「code grant flow」フローの解説があり、このフローに対して、

OpenID Connect

これを拡張したのが OpenID Connect です。 基本的な流れとして、OAuth 2.0 認可コードグラントフローをベースにした認可コードフローがあります。 この黄色い部分が OAuth 2.0 から変わっているところなんですけれども、アクセストークンと一緒に ID トークンも渡します。

https://www.authlete.com/ja/resources/videos/20200131/01/

⇧「OpenID Connect」の機能をマージしたフローを解説してくれている。

なるほど、登場人物の用語を整理すると、

No OAuth 2.0 OpenID Connect
1 Resource Owner Resource Owner
2 User Agent User Agent
3 Client RP(Relying Party)
4 Authorization Server IdP(Identity Provider) Authorization Server
5 Resource Server UserInfo Endpoint

ということになるらしい。

つまり、OpenID Connectを適応した場合に、OAuth 2.0で定義している用語の名称とOpenID Connectで定義している名称が一部異なってくるということらしい。

上記の対応表でいうと、No.3とNo.5の名称が異なっているのと、OpenID Connect側では、No.4とNo.5をまとめて、「IdP(Identity Provider)」としていると。

 \mathsf{ OAuth } \ \mathsf{ 2.0 } \ + \ \mathsf{ OpenID } \ \mathsf{ Connect}

とすることで、「RP(Relying Party)」側で検証の処理(「ユーザーの識別」)を挟むことで、脆弱性のリスクを排除した「認証」を実現するということのよう。

「RP(Relying Party)」側で『「アクセストークン」+「IDトークン」』のパース処理とかしてるのかは分からんのだけど、「カット&ペーストアタック」も防げるってことなんかな?

「UserInfo Endpoint」にあたるサーバーで、「アクセストークン」が悪意のあるサイトから送られてきたものでないかの検証をしなくて良いのかが気になりますが、「RP(Relying Party)」側での検証が済んでいれば安全として良いんかな?

「RP(Relying Party)」側での検証後に、「UserInfo Endpoint」にあたるサーバーに「アクセストークン」を送るまでの間に、「カット&ペーストアタック」が発生することは無いと考えて良いのかどうかが気になるんよな...

「ID トークン」の制約なんかは、

ID Tokens MUST be signed using JWS [JWS] and optionally both signed and then encrypted using JWS [JWS] and JWE [JWE] respectively, thereby providing authentication, integrity, non-repudiation, and optionally, confidentiality, per Section 16.14. If the ID Token is encrypted, it MUST be signed then encrypted, with the result being a Nested JWT, as defined in [JWT]. ID Tokens MUST NOT use none as the alg value unless the Response Type used returns no ID Token from the Authorization Endpoint (such as when using the Authorization Code Flow) and the Client explicitly requested the use of none at Registration time.

https://openid.net/specs/openid-connect-core-1_0.html

⇧ 上記のような感じになるらしい。

とりあえず、

  • JWS(JSON Web Signature)
  • JWE(JSON Web Encryption)
  • JWT(JSON Web Token)

⇧ 上記のような機能を組み合わせて、JSONJavaScript Object Notation)を「エンコード」したものが、「ID トークン」らしいと思ったら、

qiita.com

なお、この例では、ペイロード部分の元データが上記のように JSON となっていますが、RFC 7515 自体は JSON を要求しておらず、任意のデータ (an arbitrary sequence of octets) で構わないとしています。

IDトークンが分かれば OpenID Connect が分かる #OAuth - Qiita

⇧ とあって、まさかの、JSONJavaScript Object Notation)以外を含んでも良いらしいというね...

他のドキュメントも読み込まないと答えに辿り着けないとか、難易度が高いし、工数が嵩むから、解説サイトには感謝しか無いですな。

で、「IDトークン」の構成は、基本的には、

darutk.medium.com

Once again, ID Token is a kind of JWT.

https://darutk.medium.com/understanding-id-token-5f83f50fa02e

ID Token contains claims about user authentication and other claims. Main claims are explained in “2. ID Token” and “5.1. Standard Claims” in OpenID Connect Core 1.0. In addition, “3.3.2.11. ID Token” defines at_hash claim and c_hash claim.

https://darutk.medium.com/understanding-id-token-5f83f50fa02e 

⇧ 上記の説明にあるように、

  • ID token
    1. Header
    2. Payload
    3. Signature

という、3つの要素で構成されているらしいのだけど、それ以外にも、

4. JSON Web Encryption (JWE)

さて、ID トークンの形式には、これまで説明してきた「ヘッダー.ペイロード.署名」の他に、次のように 5 つのフィールドを持つ形式もあります。

 
ヘッダー.キー.初期ベクター.暗号文.認証タグ

この形式は、RFC 7516 (JSON Web Encryption (JWE)) の「7.1. JWE Compact Serialization」で定義されている「JSON Web Encryption (JWE) の Compact Serialization 形式」です。具体的には次のように定義されています。 (RFC 7516 は JSON Serialization 形式も定義していますが、ここでは扱いません。)

 
BASE64URL(UTF8(JWE Protected Header)) || '.' ||
BASE64URL(JWE Encrypted Key) || '.' ||
BASE64URL(JWE Initialization Vector) || '.' ||
BASE64URL(JWE Ciphertext) || '.' ||
BASE64URL(JWE Authentication Tag)

この形式は、ID トークンを暗号化したいときに利用されます。

IDトークンが分かれば OpenID Connect が分かる #OAuth - Qiita

⇧ 5つの要素で構成されていたりするパターンもあるということで、「ID トークン」の構成のパターンの全量が把握し辛い...

で、

説明が前後してしまいましたが、ID トークンは JWT の一種です

IDトークンが分かれば OpenID Connect が分かる #OAuth - Qiita

⇧ とあるので、「ID トークン」の構成の一部に、JSONJavaScript Object Notation)以外が含まれても良いのだけど(「ペイロード」部分は任意のデータで良いとあったので。ただ、「OpenID Connect」の仕様としては、データに含めないといけないものが決まっているらしいので、「ペイロード」部分については、データのフォーマットが任意ということになると思われる)、全体としては、「JWT(JSON Web Token)」の形になっている必要があると。

話が脱線しましたが、「RP(Relying Party)」側で「デコード」して「ペイロード」部分を検証することで「ユーザーの識別」を行っているということですかね。

ペイロード」部分は、「OpenID Connect」では「claims」と呼ばれるものを設定するらしく、「ユーザーの識別」ができる情報を含めるようにするようです。

「claims」にも様々な種類があるようですが、

RFC 7519 の立場から見ると、OpenID Connect Core 1.0 が定める ID トークンは、JWT 応用例の一つとなります。勘の良い方はすぐに予想されたかもしれませんが、ID トークンの仕様では、RFC 7519 で定義されているクレームの幾つかが必須のクレームとされています。具体的には、isssubaudexpiat は必須とされています。

IDトークンが分かれば OpenID Connect が分かる #OAuth - Qiita

⇧「OpenID Connect」の仕様として必須になっている「claim」がある模様。

つまり、「ペイロード」部分のデータの中身は、適切な構成にする必要があるっぽいので、どういうフィールドと内容で構成するのかが分かるIF(インターフェイス)の仕様書が欲しいところですな。

サーバーサイド側で「ユーザーの識別」ができる情報が用意されているということは、事前に、ユーザー登録などが済んでいるという前提の話ってことになりそうですね。

ちなみに、JavaSpring Frameworkを使っているような場合は、

spring.pleiades.io

⇧ Spring Securityで、OpenID Connectの「ID トークン」を導入するための機能を実装する用のAPIは用意されているっぽい。

とりあえずは、

  • 「OAuth 2.0」の機能のみでは脆弱性のリスクを排除した「認証」を実現するのは不可能である
  • 脆弱性のリスクを排除した「認証」を実現には、「OAuth 2.0」+「OpenID Connect」ないしは、類似した機能が必要である

ということが言えると。

まぁ、将来的に、他にも有効な手立てが確立されるかもしれませんが、

 \mathsf{OAuth} \ \mathsf{ 2.0} + \mathsf{ \Large{α} }

で「認証」「認可」を実現すべきと考えておいた方が良さそうってことですな。

その後で、「生体認証」とかを取り入れたりする感じになるということでしょうかね。

2024年3月17日(日)追記:↓ ここから

どうやら、

logmi.jp

OAuth 2.0とAuthleteを組み合わせる

参考までにOAuth 2.0とAuthleteを組み合わせるとどういうフローになるのか。Authleteの背景にある哲学とは何かというと、エンドユーザー認証というのはいっぱいあります。ログインIDとパスワードで認証するもの、指紋認証虹彩認証もあるし、multi-factor authenticationなど。ユーザー認証もいっぱいあるんだけど、いずれも最終的にはエンドユーザ一の一意識別子を特定する処理である、という割り切り方をしています。

OAuthやOpenID Connectの実装におけるデプロイメントパターン - ログミーTech

⇧ 上記サイト様の説明にありますように、「認証方法」に依らず、「ユーザーの識別」に焦点を当てる方針で考えた方が良さそう。

2024年3月17日(日)追記:↑ ここまで

「多要素認証」とかもリスクヘッジのために考案されたということだとは思うのだけど、「認証」「認可」周りの機能を実現するために環境構築するのが辛いですな...

とりあえず、

qiita.com

qiita.com

⇧ 上記サイト様の内容は、一通り読んでおいた方が良さそう。

兎にも角にも、「認証」「認可」周りは、登場人物が多過ぎるのと、前提条件が端折られていたりと、上手く整理してくれているサイトが少ないんよな...

2024年3月17日(日)追記:↓ ここから

ちなみに、

 \mathsf{ OAuth } \ \mathsf{ 2.0 } \ + \ \mathsf{ OpenID } \ \mathsf{ Connect}

のシーケンス図で、何故か、ユーザー情報を保持していると思われる「データベース」系のサーバーが出て来ないのだけど、

dev.to

⇧ 上記サイト様のシステム構成概要図のように、「Authorization Server」は何某かの「データストア」系のサーバーから「ユーザーの識別」に必要な「ユーザー情報」を取得してるはずだと思うんだけど、省略されてるんよね...

「Authorization Server」(「OpenID Connect」では、「IdP(Identity Provider)」の内の1つ)内に「データベース」を同梱しているなら、分かるように注釈を入れてくれたら良いのだけど、

 \mathsf{ OAuth } \ \mathsf{ 2.0 } \ + \ \mathsf{ OpenID } \ \mathsf{ Connect}

のシーケンス図で、そのあたりに触れてくれている情報が皆無なんよね...

2012年頃から「OAuth 2.0」の「認証」の脆弱性の議論がされてる割には、正確なシーケンス図1つ作られていないってのは、残念過ぎる...

有識者の人に頑張ってもらいたかったんですけどね...

Authleteの方が、

logmi.jp

⇧ 上記サイト様の中で、

 \mathsf{ OAuth } \ \mathsf{ 2.0 } \ + \ \mathsf{ OpenID } \ \mathsf{ Connect}

について整理していただいているようで、目を通しておいた方が良さそう。

2024年3月17日(日)追記:↑ ここまで

毎度モヤモヤ感が半端ない...

今回はこのへんで。