OAuth/OpenID Connect

OAuth/OpenID Connect #

概要 #

本章では、OAuth 2.0およびOpenID Connect(OIDC)と、それに関連するしくみについての脆弱性や攻撃手法について説明します。 なお、本ドキュメントに記載する用語、パラメータ名などはRFC 6749およびOpenID Connect Core 1.0 incorporating errata set 1の記載に準拠します。

OAuth 2.0 #

OAuth 2.0は、リソースサーバや認可サーバから見てサードパーティとなるクライアントサーバやアプリケーション等が、その認可に応じてリソースサーバに保存されているリソースオーナの情報を得るための認可フレームワークです。 通常のアプリケーションのようにクライアント/サーバだけではなく、認可サーバ/リソースサーバを含めた三者間の関係でセキュリティを考慮する必要があります。そのため、各パラメータの目的を考えながら、仕様通り正しく実装する必要があります。

以下では代表的な脆弱性の概要や診断手法について記載します。

オープンリダイレクタ #

概要 #

認可サーバでの認可が完了すると、リソースオーナのブラウザはredirect_uriパラメータで指定されたURLへリダイレクトされます。 このリダイレクト時にオープンリダイレクタの脆弱性が存在すると、リソースオーナのブラウザが攻撃者の管理するサーバへリダイレクトされ、認可コード/アクセストークンが漏えいします。

原因と影響 #

認可リクエスト中のredirect_uriパラメータで指定されるリダイレクト先を検証することなく、認可レスポンスのLocationヘッダにそのまま設定していることが原因です。 これによって、被害者(リソースオーナ)が同意した結果を表す認可コードが、攻撃者の指定するURLへ誘導されます。その結果、認可コードが漏えいし攻撃者にアクセストークンを発行される可能性があります。 また、クライアントがImpicit Flowを利用している場合は、認可コードではなくアクセストークンが漏えいします。 なお、認可コード/アクセストークンの漏えいが難しい場合であっても、任意のURLへリダイレクト可能であれば、一般的なオープンリダイレクタと同様の脅威が存在します。

診断観点 #

診断時においては、認可リクエスト中のredirect_uriに対して任意のURLを指定し、認可レスポンス受信時にそのURLのリダイレクトが発生するかを検証します。 また、不正なscopeの設定など、redirect_uri以外のパラメータの改ざんなどエラーを引き起こし、その際にredirect_uriで指定したURLへのリダイレクトが発生するかも検証します。

対策 #

オープンリダイレクタは認可サーバ側での対策が必要です。 クライアントに対してredirect_uriの事前登録を必須とし、認可リクエスト中のredirect_uriパラメータと完全一致が検証できた場合にのみ、認可レスポンスを返す実装とします。

また保険的な対策として、アクセストークンリクエスト中のredirect_uriパラメータの値が、認可リクエストにて送信されていたredirect_uriパラメータの値と、一致することを検証する方法もあります。 これにより、仮にオープンリダイレクタによって漏えいした認可コードを悪用された場合であっても、認可リクエスト中のredirect_uri(攻撃者が指定したURL)とアクセストークン中のredirect_uri(クライアントの正規のURL)が一致しないため、不正なアクセストークン発行を防ぐことが可能です。

クロスサイトリクエストフォージェリ #

概要 #

OAuth 2.0におけるstateパラメータは、端的にはCSRF攻撃を防ぐためのパラメータです。 本パラメータに着眼して認可コードフローを見ると、以下のようになります。

  1. クライアントサーバは、stateとしてランダムな値を発行し、リソースオーナーのブラウザのセッションと紐づけて保存する
  2. ブラウザは、クライアントサーバから発行されたstateを含む認可サーバへのURLへアクセスする
  3. 認可サーバは、codeパラメータとともに(2)のリダイレクト時に受け取ったstateをURLに付与してブラウザをクライアントサーバへリダイレクトさせる
  4. クライアントサーバは、ブラウザからcodeとstateを受け取り、(1)で保存したstateと一致している場合は以降の処理を実施する

このフローにおいてstateパラメータの検証を適切に行っていない場合、以下の手順で攻撃が可能となります。

  1. 攻撃者は、上記フローにのっとって発行された自身のcodeを用いて、そのcodeを付与して被害者ブラウザをクライアントサーバへリダイレクトさせるような罠サイトを作る
  2. 罠サイトにアクセスした被害者のセッションと攻撃者のcodeの組をクライアントサーバで処理される
  3. 被害者は、攻撃者のアカウントでログインした状態となる

原因と影響 #

前述の通り、原因は、クライアントサーバが、codeパラメータを受け取る際に、stateパラメータを検証していないことです。 これによって、攻撃者のアカウント向けに発行されたcodeパラメータを、被害者に強制させることができます。

この影響はサイトや機能によって異なります。 たとえば、会員登録後に他サイトのアカウントと連携設定することで当該サイトのアカウントで会員としてログインできる機能をもったサイトの場合を考えます。この場合、連携設定の際に攻撃者アカウントのcodeを被害者のセッションに強制することで、攻撃者アカウントで当該サイトに被害者としてログインできます。

診断観点 #

診断時においては、CSRFの観点からstateパラメータを検証する必要があります。

OAuthはその性質上セッションを維持したまま外部サイトからのGET等を受け付ける必要があります。このため、SameSite属性によってCSRFを防いでいるサイトであっても、CSRF可能となる場合があるので、注意が必要です。

対策 #

処理前に十分にランダムなstateを付与し、codeパラメータを処理する前にセッションから読み出したstateとリダイレクトによって送られてきたstateが同一であるかを検証します。

コードインジェクション #

概要 #

コードインジェクションとは、攻撃者自身の管理下にあるアプリケーションに対して、OAuthまたはOIDCのリダイレクト時に認可コードを第三者の未使用の認可コードに入れ替える攻撃です。

原因と影響 #

OAuthにおいては、Authorization Code Grantを利用しているクライアントアプリがPKCEを利用していない、もしくは認可サーバがPKCEに対応していないことが原因です。 OIDCにおいては、nonceまたはc_hashを利用していないことが原因です。 攻撃者はあらかじめクライアントアプリに対して発行された、被害者となるリソースオーナーの認可コードを取得します。 そして、認可レスポンスの Location ヘッダに含まれるURIのクエリパラメータの認可コードの値をあらかじめ取得した被害者の認可コードと入れ替えます。 これにより、攻撃者はリソースオーナーのリソースに不正にアクセスできます。

診断観点 #

OAuthのフロー開始後、PKCE関連のパラメータが送信されているか、その値が適切に検証されているかを検査する必要があります。 認可リクエストにおいては、code_challengeおよびcode_challenge_method パラメータが送信されているかを確認します。 送信されている場合にはいずれか一方の値を適当な値に改ざんしてもフローが正常に完了するか検査します。 トークンリクエストにおいては、code_verifierを含めないもしくは正規のcode_verifier以外の値に改ざんしてもフローが正常に完了するか検査します。

OIDCのフロー開始後、IDトークンのnonceまたはc_hashがクライアントアプリで適切に検証されているか検査する必要があります。 認証リクエストにおいて、nonceもしくはcodeを入れ替えることでフローが正常に完了するか検査します。

対策 #

OAuthのコードインジェクション対策として、PKCEに準拠した実装が有効です。PKCEにより認可サーバで認可コードの入れ替えを検知できます。

OIDCのコードインジェクション対策として、nonceとc_hashがあります。 nonceを利用することで、IDトークンと認証リクエストを紐づけることが可能となります。クライアントアプリがIDトークンを受け取ったら、nonceを検証することで、トークンレスポンスにおいて攻撃を検知できます。 c_hashが利用できるのは response_typeの値にid_tokenとcodeの両方が含まれるハイブリッドフローです。クライアントアプリがIDトークンのc_hashを検証することで、認証レスポンスにおいて攻撃を検知できます。

クライアント認証の不備 #

概要 #

アクセストークンリクエストは、アクセストークン取得のためにクライアントから認可サーバ宛に送信されるリクエストです。アクセストークンリクエスト時にはクライアント認証が必須とされており、ここでの認証に不備があると、正規のクライアントになりすましてアクセストークンを発行可能となります。

原因と影響 #

認可サーバが、アクセストークンリクエスト受信時にクライアントへ認証を要求していないことが原因です。 このような場合、何らかの手段で漏えいした認可コードを用いて、正規のクライアントになりすましたアクセストークンを発行される可能性があります。

診断観点 #

認可サーバから得たアクセストークンをサーバに送信していたり、そのアクセストークンによって解決した情報をサーバに送信している場合は注意が必要です。その値が改ざん可能であることを留意した設計になっているか検証する必要があります。

対策 #

アクセストークンリクエスト送信時に、クライアントへ認証を要求します。ここでの認証方式は厳密に指定されておらず、パスワード認証やクライアント証明書などが利用可能です。

Implicit Grant Flowをサーバと関係した処理で用いる #

概要 #

Implicitフローは認可サーバとリソースオーナーのユーザエージェントのみで構成されるアプリケーションにおいて使える機能です。このフローで得た情報をサーバに送信する場合、当該値はリソースオーナーによって改ざん可能であるため、信頼できない値として扱う必要があります。

原因と影響 #

たとえばImplicitフローで得られたリソースオーナーの住所をサーバに送信して、リソースサーバから連携された身元情報として取り扱う場合を考えます。この場合攻撃者は、リソースサーバから得られた住所を改変して送信することで、リソースサーバによって検証されていない値を登録できます。

また、クライアントがアクセストークンをリソースオーナーのユーザエージェントから直接受け取っている場合、リソースオーナーは任意のアクセストークンを送信できます。よって当該クライアント向けに発行されたものであるか検証しない限り、攻撃者サーバを利用したユーザのアクセストークンを使って、対象サイト上の機能を悪用できる可能性があります。

対策 #

認可サーバとリソースオーナのユーザエージェント以外が関与する場合はImplicitフローではなく、認可コードフローを用いてください。

OpenID Connect #

OpenID Connectにおいても、その一部はOAuth 2.0と同様の処理であるため、その共通する処理に関しては前述の問題が起こり得ます。 ただし、OpenID Connect特有の問題もあります。以下ではその問題について解説します。

IDTokenの検証不備 #

概要 #

OpenID Connectにおいては、最終的にユーザのアイデンティティを証明するものとして、JsonWebTokenが発行されます。このトークンには発行元や発行先、有効期限などが保持されており、署名によって正当性を検証できるようになっています。 正当性検証を怠った場合、JWT改ざんによって、なりすまし等の被害を発生させる恐れがあります。

原因と影響 #

トークンの署名検証に不備がある場合、攻撃者はトークンを改ざんできるため、JWT内のパラメータを改ざんすることで、なりすますことが可能です。alg:Noneを指定できる場合や、攻撃者にとって既知の鍵を用いている場合などが不備の典型例です。

診断観点 #

alg none #

署名検証不備を狙う攻撃として著名なものにJWTヘッダのalgの値にnoneを設定し、署名検証を回避させるものがあります。IDトークンの検証者がnoneの設定を許容している場合、IDトークンに含まれるclaimの値を攻撃者が自由に改ざん可能となり、第三者へのなりすましが容易に可能となります。

alg hs256 #

noneがIdPによって拒否された場合、別のアルゴリズムを指定することで署名検証の不備を突破できる可能性があります。それはHS256です。改ざん対象のIDトークンの署名に用いられた秘密鍵と対になるIdPの公開鍵を特定し、その公開鍵を用いてIDトークンの署名を生成します。この時のIDトークンは、ヘッダのalgの値としてHS256を指定した新たなIDトークンとして生成します。署名に用いたIdPの公開鍵をkidパラメータなどで指定できる場合、IDトークンに含まれるclaimの値を攻撃者が自由に改ざん可能となり、第三者へのなりすましが容易に可能となります。

対策 #

まず署名検証を正しく行う必要があります。自身がRPの場合、署名検証アルゴリズムは独自に実装せず、ライブラリ等を用いて検証しましょう。自身がIdPを担う場合は、ライブラリ使用に加え、JWT署名専用の鍵を生成・保管し鍵を使いまわさないようにしてください。  加えて、自身がRPの場合は利用しているIdPが各クレームをどのように用いているか念のため確認することを推奨します。IdPが推奨する利用法や実装に沿って認証機能を実装しましょう。自身がIdPの場合は、仕様に沿って各クレームを実装してください。仕様書にないクレームを付与する場合は、その意味や想定される使い方を公開してください。

リプレイアタック #

概要 #

リプレイアタックとは、すでにRPで利用されたIDトークンを再送することで、正規のユーザになりすましてRPへログインすることを試みる攻撃です。 すでに利用済みのIDトークンを利用することから、正規のOIDCフローが完了した後に懸念されます。

原因と影響 #

リプレイアタックが発生する原因にはRPとOPそれぞれの実装不備が関与します。

RP #

ユーザのセッションと紐づくnonceパラメータを認証リクエストに含めていない、もしくはトークンレスポンス受信時にnonceパラメータを削除していないことが原因です。

OP #

IDトークンのclaimに、認証リクエストで受け取ったnonceパラメータを含めていないことが原因です。 これによって、何らかの手段でIDトークンを入手した攻撃者によって、正規のユーザになりすましてRPへログインされる可能性があります。

診断観点 #

診断時においては、IDトークンの再送が可能であるかを検査します。 手順として、まず一度OIDCのフローを完了してIDトークンを発行します。その後、別のユーザとしてOIDCのフローをあらためて開始し、トークンレスポンス内のIDトークンを、最初に発行したIDトークンへ置き換えます。その結果、最初にIDトークンを発行したユーザとしてRPへログインに成功する場合、リプレイアタックが可能となります。

対策 #

RPとOPのそれぞれで対策が必要です。

RP #

以下3点のどちらの対応も必須です。

  • ユーザのセッションに紐づく値を生成し、認証リクエストにnonceパラメータとして含める
  • IDトークンのclaim内のnonceパラメータとユーザのセッションに紐づく値が一致することを検証する
  • 検証後にセッションからnonceに一致する値を削除する

OP #

認証リクエストにnonceパラメータが含まれている場合は、発行するIDトークンのclaimにそのnonceパラメータをそのまま含める。