Alternative Architecture DOJO

オルターブースのクラウドネイティブ特化型ブログです。

OpenID Connect と OAuth 2.0 を知りたい

こんにちは。オルターブースの横野です。 この記事はオルターブース アドベントカレンダー 2023 の21日目の記事になります。

adventar.org

アドベントカレンダー2023も残すところあとわずか!

私は最近、業務で認証まわりを触ることが多いのですが、そもそも認証プロトコルについてちゃんと理解できているのかな?

と思い調べてみたところ、多くの素晴らしい書籍や記事が存在していたので、その内容を整理するイメージで書いていきます。

とはいえ今回の記事はタイトルにもある通り「OpenID Connect と OAuth 2.0 を知りたい」といった感じで非エンジニア~初心者向けに書いていこうと思いますので詳細なことを求めている方にはつまらないかも知れません…。

現在では「OpenID Connect」「OAuth 2.0」「FIDO 2.0」「SAML 2.0」などのプロトコルが標準化されていますが、その辺の仕様などについて細かく書いていくのではなく、当記事ではまず「OpenID Connect」「OAuth 2.0」について概要レベルで誰かの足がかりになれればいいな~と考えております。

認証と認可について

さて、まずは認証と認可について話していきます。ご存じかと思いますが、認証と認可は似ているようで全然違います。スイカとスイカバーくらい違います。

認証(Authentication)は「ユーザーが本人の主張通りのユーザーであるか。誰であるかを確認し、証明すること」に対して、認可(Authorization)は「権限(Authority)についての概念であり、特定のリソースや機能へのアクセス権限をユーザーに与えるプロセス」です。

認証 認可
ユーザーが本人の主張通りのユーザーであるか。誰であるかを確認し、証明すること 特定のリソースや機能へのアクセス権限をユーザーに与えること

ザックリいうと、例えば海外へいく時パスポート(認証)で国際的な身分を証明書し、ビザ(認可)の種類によって活動の制限があるようなイメージを思い浮かべてもらえればいいかと思います。

アプリケーションにおける認証での一般的な方法は ID とパスワードを提示してもらうことで、ユーザーの一意な識別子を証明することになり、認可に関しては「誰が」「誰に」「何の権限を与えるか」のプロセスとなります。

お気づきかと思いますが、認可の「誰が」というのが認証にあたり、認可には認証が内包されている形となります。

OAuth2.0 と OpenID Connect

では本題に入っていきます。

OpenID Connectってなに?OAuth 2.0ってなに?と聞かれてサクっと答えれる方はいますでしょうか?(たくさん居そうで怖いw)

正直にいうと実は私の場合、「 OpenID Connect = 認証 OAuth 2.0 = 認可」くらいに思っていました💦

OpenID Connect は OAuth 2.0 をベースに拡張したものなのです。ですので実質的に OAuth 3.0 などと唱える方がいたり、以下のように OAuth 2.0 と Identity, Authentication を足したものが OpenID Connect だと定義される方もよく見かけます。

(Identity, Authentication) + OAuth 2.0 = OpenID Connect

そしてOAuth認証なんていう言葉を聞いたことはありますでしょうか。

確かに OAuth 2.0 は認可なので先に述べた認証機能も備えられているはずです。ですので OAuth 2.0 で認証をおこなうことは可能なのです。

ではなぜ OpenID Connect で OAuth 2.0 を拡張する必要があったのかというと OAuth認証 には大きなセキリティホールがあります。OAuth 2.0 は、あくまで認可のための仕組みであり認証に使うにはリスクが非常に高いと考えられたからです。

ざっくりいうと OAuth 2.0 では認証に access_token を使用しているが、 access_token では「いつ」「どこで」「なんのために」作られたのかが不明であるということです。

なので access_token の置換え攻撃が可能で OAuth 2.0 のstateパラメータを使って XSRF 対策をしても防ぐことができません。

この辺りをもっと詳細に知りたいという方はぜひご自身で深掘りされてみるとよいかと思います。

【参考ドキュメント】 www.thread-safe.com

OAuth2.0 と OpenID Connect の違い

では OAuth2.0 と OpenID Connect では何が違うのか。

様々な違いがあると思いますが、大きな違いをあげると OpenID Connect では id_token が発行され OAuth 2.0 では access_token が発行されることです。

id_token は「いつ」「どこで」「なんのために」作られたのかの情報が含まれており、トークンの署名やオーディエンスを検証してユーザーの認証を確認することが可能です。

そして id_token はJWT(JSON Web Token)という形式の文字列になります。

JWTについて

JWT は JSON 形式で表された認証情報などを URL 文字列などとして安全に送受信できるように符号化やデジタル署名の仕組みを定めた標準規格です。

JWT は、「ヘッダー」「クレーム」「署名」の3つの部分に分かれていて、それぞれ Base64 URL 方式をエンコード(符号化)して「.」で連結したものがトークンとなります。

id_token の例:

eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsIng1dCI6IjdfWnVmMXR2a3dMeFlhSFMzcTZsVWpVWUlHdyIsImtpZCI6IjdfWnVmMXR2a3dMeFlhSFMzcTZsVWpVWUlHdyJ9.eyJhdWQiOiJiMTRhNzUwNS05NmU5LTQ5MjctOTFlOC0wNjAxZDBmYzljYWEiLCJpc3MiOiJodHRwczovL3N0cy53aW5kb3dzLm5ldC9mYTE1ZDY5Mi1lOWM3LTQ0NjAtYTc0My0yOWYyOTU2ZmQ0MjkvIiwiaWF0IjoxNTM2Mjc1MTI0LCJuYmYiOjE1MzYyNzUxMjQsImV4cCI6MTUzNjI3OTAyNCwiYWlvIjoiQVhRQWkvOElBQUFBcXhzdUIrUjREMnJGUXFPRVRPNFlkWGJMRDlrWjh4ZlhhZGVBTTBRMk5rTlQ1aXpmZzN1d2JXU1hodVNTajZVVDVoeTJENldxQXBCNWpLQTZaZ1o5ay9TVTI3dVY5Y2V0WGZMT3RwTnR0Z2s1RGNCdGsrTExzdHovSmcrZ1lSbXY5YlVVNFhscGhUYzZDODZKbWoxRkN3PT0iLCJhbXIiOlsicnNhIl0sImVtYWlsIjoiYWJlbGlAbWljcm9zb2Z0LmNvbSIsImZhbWlseV9uYW1lIjoiTGluY29sbiIsImdpdmVuX25hbWUiOiJBYmUiLCJpZHAiOiJodHRwczovL3N0cy53aW5kb3dzLm5ldC83MmY5ODhiZi04NmYxLTQxYWYtOTFhYi0yZDdjZDAxMWRiNDcvIiwiaXBhZGRyIjoiMTMxLjEwNy4yMjIuMjIiLCJuYW1lIjoiYWJlbGkiLCJub25jZSI6IjEyMzUyMyIsIm9pZCI6IjA1ODMzYjZiLWFhMWQtNDJkNC05ZWMwLTFiMmJiOTE5NDQzOCIsInJoIjoiSSIsInN1YiI6IjVfSjlyU3NzOC1qdnRfSWN1NnVlUk5MOHhYYjhMRjRGc2dfS29vQzJSSlEiLCJ0aWQiOiJmYTE1ZDY5Mi1lOWM3LTQ0NjAtYTc0My0yOWYyOTU2ZmQ0MjkiLCJ1bmlxdWVfbmFtZSI6IkFiZUxpQG1pY3Jvc29mdC5jb20iLCJ1dGkiOiJMeGVfNDZHcVRrT3BHU2ZUbG40RUFBIiwidmVyIjoiMS4wIn0=.UJQrCA6qn2bXq57qzGX_-D3HcPHqBMOKDPx4su1yKRLNErVD8xkxJLNLVRdASHqEcpyDctbdHccu6DPpkq5f0ibcaQFhejQNcABidJCTz0Bb2AbdUCTqAzdt9pdgQvMBnVH1xk3SCM6d4BbT4BkLLj10ZLasX7vRknaSjE_C5DI7Fg4WrZPwOhII1dB0HEZ_qpNaYXEiy-o94UJ94zCr07GgrqMsfYQqFR7kn-mn68AjvLcgwSfZvyR_yIK75S_K37vC3QryQ7cNoafDe9upql_6pB2ybMVlgWPs_DmbJ8g0om-sPlwyn74Cc1tW3ze-Xptw_2uVdPgWyqfuWAfq6Q

URLセーフな文字列なのでHTTPヘッダーやURLパラメータとして送受信でき、クレームに任意のデータを含めれるため様々な情報伝達ができ、署名によりデータの信頼性を保てます。

またサーバー側でセッション情報を保持する必要がないため、ステートレスな認証や分散システムに向いています。

ヘッダー

トークンや署名の形式についての情報を格納する部分で、「alg」フィールドに署名アルゴリズムが「typ」フィールドにトークンの種類を示す文字列が「kid」フィールドに Key ID が入ります。

「kid」は JWT をデジタル署名により JWS ヘッダーにしたい場合、公開鍵を特定して署名を検証するために使用されます。

フィールド 説明
alg 署名アルゴリズム。"RS256" など
typ トークンの種類を示す文字列。"JWT"
kid Key ID

クレーム

伝える情報の本体部分で、システムが必要とするデータを任意に指定することができる。規格上意味がある「登録済みクレーム」を使うことができ「iss」(発行者)、「sub」(主題)、「aud」(受信者)、「exp」(有効期限)、「sud」(トークンの受け手)、などのクレームが入る。任意のクレーム「email」(メールアドレス)なども含めることが可能

クレーム 説明
iss 発行者
sub 件名。トークンが情報をアサートするプリンシパル (アプリケーションのユーザーなど)
aud 受信者
exp トークンの有効期限
sud トークンの受け手

署名

トークンの作成者の本人確認に用いるデータで、ヘッダーとペイロードを符号化したものを繋げて署名アルゴリズムを計算することで生成される。

受信側でも検証することで改ざんや、偽造がおこなわれていないか確認することができる

AzureAD B2Cの id_token 例

ここで、Azure のサービスである AzureAD B2C ( AADB2C )で id_token を用いた時の例をご紹介していきます。

【参考ドキュメント】 learn.microsoft.com

以下は私が実際に AADB2C で id_token を用いて認証をおこなった際の JWT です。

※公開したくない情報は一部修正しております

// ヘッダー
{
  "alg": "RS256",
  "kid": "X-XXXX...XXXXXXXXXXXXXXXXXXXXXXXXXXXXX-XXXX",
  "typ": "JWT"
}.
// クレーム
{
  "ver": "1.0",
  "iss": "https://yourtenant.b2clogin.com/XXXXX...-XXXX-XXXX-XXXX-XXXXXXXXXXXX/v2.0/",
  "sub": "XXXXX...-XXXX-XXXX-XXXX-XXXXXXXXXXXX",
  "aud": "XXXXX...-XXXX-XXXX-XXXX-XXXXXXXXXXXX",
  "exp": 1701835986,
  "email": "youremail@example.com",
  "acr": "b2c_1a_signup_signin",
  "nonce": "defaultNonce",
  "iat": 1701832386,
  "auth_time": 1701832386,
  "name": "yourname",
  "tid": "XXXXX...-XXXX-XXXX-XXXX-XXXXXXXXXXXX",
  "customparameter": "{OAUTH-KV:xxx}",
  "nbf": 1701832386
}.
// 署名
[Signature]

上記の 「JWTについて」で紹介したもの以外では以下のようなクレームがあります。

クレーム 説明
ver ID トークンのバージョンです。AADB2C で定義されている
email ユーザーのメールアドレス
acr AADB2C 認証時に使うユーザーフローの PolicyId
nonce トークンのリプレイ攻撃を緩和するために使用される
iat トークン発行日時
auth_time ユーザーが資格情報を最後に入力した時刻
name ユーザーの名前
tid AADB2C テナントのディレクトリID
customparameter カスタムポリシーで定義したカスタムURLパラメータ用クレーム
nbf トークンが有効になる日時

試しに AADB2C のトークン有効期間を計算してみると、以下のように1時間であることが分かりました。

exp(有効期限): 1701835986 - iat(トークン発行日時): 1701832386 = 3600 (sec)

このように AADB2C の場合の id_token にも「いつ」「どこで」「なんのために」作られたのかの情報が含まれており、トークンの署名やオーディエンスを検証してユーザーの認証を確認可能なことが分かりました。

まとめ

OpenID Connect と OAuth 2.0 の違いやどうして OpenID Connect は OAuth 2.0 を拡張する必要があったか、なぜ安全に認証できるのかなどを知れたので OpenID Connect を少しだけ理解することができたと感じました。

また AADB2C でユーザーフローやカスタムポリシーを使用する時、JWT のヘッダーやクレームに何がどのような用途で入っているのかという理解が深まりました。

ただ残念なことに今回は検証が少なめでしたので、もし次に OpenID Connect や OAuth 2.0 関連の記事を書くことがあれば、ぜひ検証を多く盛り込んだような記事を書いてみたいです。


サービス一覧 www.alterbooth.com cloudpointer.tech www.alterbooth.com