日本語
  • セキュリティ
  • oauth
  • PKCE

簡単なOAuthセキュリティの再確認

OAuthによる保護措置についてどの程度理解していますか? あなたのシステムは、OAuthのオープンスタンダードに対応していますか? ユーザー認証フローの実装中に生じる可能性のあるリスクを気にしていますか? OAuthについて学んだことを簡単に再確認してみましょう。

Simeng
Simeng
Developer

序章

数日前、興味深いOAuthの脆弱性に関する記事が出ました。 A-new-oauth-vulnerability-that-may-impact-hundreds-of-online-services は、SALT labによるものです。この記事では、OAuthやその他の機能を実装するために広く使用されているフレームワークである Expo で発見された脆弱性が強調されています。それは具体的にはexpo-auth-sessionライブラリの脆弱性を指摘し、すでに正しく修正されています。

OAuthに興味がある方や、私たちのようにCIAM関連の製品に取り組んでいる方には、この記事を読むことを強く推奨します。非常に刺激的であり、有益な洞察を提供します。これらのホワイトハットの報告は、たとえ最も単純な機能でも脆弱性を引き起こす可能性があることを思い起こさせます。サイバーセキュリティや認証に関しては、ユーザー情報のセキュリティとプライバシーを確保するために、いくら注意深くても過言ではありません。この記事があなたの興味を引けば、私たちに強く同意すると思います。

私たちが初めて始めたときを思い出します。私たちはOAuthとOIDCプロトコルの詳細について学び、研究するために多くの時間を費やしました。それは困難で退屈だったが、その利益は大きかった。チームの各メンバーがOAuthのエキスパートではないかもしれませんが、すべてのメンバーがセキュリティと入念さに対する継続的な取り組みを続けることに専念しています。これらの専心的な努力によって、Logtoの商品は現在のように進化しました。

この素晴らしい機会に感謝し、ここでOAuthのセキュリティ詳細について我々の記憶をフレッシュにしたいと思います。

OAuth認可コードフローの一覧

OAuth 2.0は、さまざまなクライアントタイプや要件に対応するためのさまざまな認可フローを提供します。これには、Implicit FlowClient Credentials FlowResource Owner Password Credentials Flow、およびDevice Authorization Flowが含まれます。ただし、Authorization Code Flowは、最も安全で広く使用されているものとして注目されています。他のフローとは異なり、ユーザー認証をクライアントアプリケーションから切り離し、Authorization Codeをトークンと交換することを含みます。このアプローチは、敏感なトークンがクライアントに公開されることがないため、セキュリティの追加レイヤーを提供します。さらに、Authorization Code Flowは、サーバーサイドのトークン管理をサポートしており、堅固なセキュリティとユーザーアクセスの強化制御を必要とするWebアプリケーションに適しています。

以下に、最も簡単なAuthorization Code Flowのダイアグラムを示します。

Authorization Code Grantフロー内で行われる2つの最も重要なリクエストと、それらに含まれているが詐欺防止に重要な役割を果たす些細な断片について見てみましょう。

認可エンドポイント:

トークン交換エンドポイント:

クライアント認証情報

OAuthでは、Client Credentialsは、クライアントアプリケーションが認証サーバーに対して自身を認証し、識別するために使用する認証情報を指します。これらの認証情報は、クライアントの登録プロセス中に取得され、認証サーバーへのリクエストを行う際にクライアントの身元を検証するために用いられます。(あなたのアプリケーションを最初に登録したときに、Logtoの管理コンソールでクライアントの資格情報を見つけることができます。)

クライアントの資格情報は、通常以下の2つのコンポーネントで構成されます。

  1. Client ID: 認証サーバーによってクライアントアプリケーションに割り当てられた一意の識別子。これは一般に公開され、敏感ではないとされる値です。
  2. Client Secret: クライアントと認証サーバーだけが知っている、秘密かつ安全に保存された値。これは、クライアントアプリケーションの一種の認証形態として機能し、認証サーバーへのリクエストを行う際にクライアントの身元を検証するために使用されます。

あなたが見つけられるかもしれませんが、Client IDとClient Secretの組み合わせは、トークンリクエストの間にクライアントを認証し、アクセストークンを取得するために使用されます。

クライアント認証情報は、OAuthフローのセキュリティを確保するための重要な役割を果たします。それらは、認証サーバーがクライアントアプリケーションの真正性を検証し、保護されたリソースへのアクセスを制御するのを助けます。クライアント認証情報を安全に取り扱い、不正アクセスから保護することが重要です。Logtoでは、クライアントアプリケーションを2つの異なるセキュリティレベルでカテゴライズします:

  • 機密クライアント: サーバー描画型のWebアプリケーションやマシン・トゥ・マシン(M2M)アプリケーションなどが含まれます。機密クライアントの場合、すべての認可関連の認証情報は、クライアント認証情報を含め、サーバーサイドで安全に保存されます。また、すべての中間交換リクエストは暗号化され、データの機密性が保たれます。機密クライアントにおけるクライアント認証情報の漏洩リスクは非常に低く、そのため本質的により安全です。したがって、ユーザーからの高いセキュリティレベルがデフォルトで提供されます。 トークン交換フローでは、Client Secretの提示は必須です。
  • パブリッククライアント: これには、シングルページWebアプリケーション(SPA)やネイティブアプリケーションが含まれます。パブリッククライアントでは、クライアントの認証情報は通常クライアント側で固定されており、JavaScriptパッケージやネイティブプラットフォームのアプリパッケージなどに含まれます。クライアントの認証情報がクライアント側のコードで露出するため、機密クライアントに比べて認証情報漏洩のリスクが高くなります。 トークン交換フローでは、Client Secretの提示はOPTIONALです。デフォルトでは、Logtoはパブリッククライアントからのこれらの資格を信頼しません。

状態

OAuthフローでは、stateパラメータは、クライアントが認証サーバーに送信する認可リクエストに含まれるランダム生成値です。その目的は、認可プロセス全体でクライアントのリクエストの状態またはコンテキストを維持することです。

stateパラメータは、cross-site request forgery (CSRF)攻撃を防ぐためのセキュリティ対策として機能します。認証サーバーがユーザーを認証と認可の後にクライアントアプリケーションにリダイレクトするとき、同じ状態値を応答に含めます。クライアントアプリケーションは、この値を認可リクエストで送信した元のstate値と比較する必要があります。

状態パラメータを検証することで、クライアントは、認証サーバーから受け取った応答が、自分が最初に行ったリクエストに対応していることを確認できます。これにより、攻撃者が他のユーザーやアプリケーションを対象とする応答をクライアントが受け入れるように詐欺する攻撃を防ぐことができます。

以下の例は、仮想的な使用例でのCSRF攻撃を示しています。

CSRF攻撃: ソーシャルアカウントの結びつけ詐欺 - 問題

適切な状態検証メカニズムを備えていると、クライアントは攻撃を検出し、ユーザーが攻撃者のウェブサイトにリダイレクトされるのを防ぐことができます:

CSRF攻撃: ソーシャルアカウントの結びつけ詐欺 - 解決策

PKCE

先述のように、SPA Webアプリやネイティブアプリケーションのようなパブリッククライアントは、認証サーバーによって発行されたAuthorization Codeを含む認証資格の漏洩リスクが高いです。

PKCEはProof Key for Code Exchangeの略で、パブリッククライアントのセキュリティを強化するOAuth 2.0 Authorization Code Flowへの拡張機能です。

PKCEは、攻撃者がAuthorization Codeを傍受し、クライアントの知らずにAccess Tokenと交換するリスクを軽減するために導入されました。この種の攻撃は、クライアントアプリケーションがクライアントシークレットを安全に保存できない環境で一般的なAuthorization Code傍受攻撃と呼ばれます。

PKCEを実装するために、クライアントアプリケーションはランダムなCode Verifierを生成し、特定のハッシュアルゴリズム(通常はSHA-256)を使用してCode Challengeを派生します。Code Challengeは、初期の認可リクエストに含まれ、認証サーバーに送信されます。

認証サーバーがAuthorization Codeを発行すると、クライアントアプリケーションは元のCode Verifierをトークンリクエストに含めます。サーバーは、Code Verifierが保存されたCode Challengeと一致することを確認し、その後にAccess Tokenを発行します。

PKCEを使用することで、クライアントアプリケーションはAuthorization CodeだけではAccess Tokenを取得するのに十分ではないことを保証します。このメカニズムは、特にClient Secretsの保存が難しいパブリッククライアントに対して、認可フローに追加のセキュリティレイヤーを追加します。

Logtoでは、PKCEを全てのパブリッククライアント型アプリケーションに対する唯一の認可フローとして使用します。しかしながら、PKCEは、それらの機密クライアントに対しては省略可能です。

リダイレクトURI

Redirect URI(Uniform Resource Identifier)は、OAuthで、認証サーバーが認証と認可のプロセス後にユーザーをリダイレクトする特定のエンドポイントまたはURLを指します。

OAuthフロー中、クライアントアプリケーションは初期の認可リクエストの一部としてRedirect URIを含めます。このURIは、ユーザーがクライアントに成功した認証と権限付与の後にリダイレクトされるコールバックURLの役割を果たします。

ユーザーが認証プロセスを完了すると、認証サーバーはAuthorization Codeを含む応答を生成し、指定されたRedirect URIにユーザーをリダイレクトします。

リダイレクトURIの検証は、OAuthフローのセキュリティと完全性を確保するための重要なステップです。それは、認可リクエストと subsequent redirectionsで使用されるRedirect URIが有効で信頼されていることを確認することを含みます。

さあ、オリジナルのOAuthの脆弱性レポートに戻ってみましょう。(以下のセクションはオリジナルの投稿から引用されています)

ユーザーがExpo GoのモバイルAPPを使って「facebookでログイン」をクリックすると、次のリンクにユーザーをリダイレクトします:

https://auth.expo.io/@moreisless3/me321/start?authUrl=https://www.facebook.com/v6.0/dialog/oauth?code_challenge=...&display=popup&auth_nonce=...&code_challenge_method=S256&redirect_uri=https://auth.expo.io/@moreisless3/me321&client_id=3287341734837076&response_type=code,token&state=gBpzi0quEg&scope=public_profile,email&returnUrl=exp://192.168.14.41:19000/--/expo-auth-session

応答から、auth.expo.ioは次のクッキーを設定します:ru=exp://192.168.14.41:19000/--/expo-auth-session. RUの値は後のステップ5でReturn Urlとして使用されます。次に、ユーザーに確認メッセージが表示され、ユーザーが承認すると、Facebookのログインにリダイレクトし、認証フローを続けます。

このページは「returnUrl」クエリパラメータを読み取り、クッキーを設定します。

hTTps://attacker.com(httpsは許可されていないので、大文字を挿入して試しました)に変更しましょう。これにより、RU(Return Url)のクッキーがhttps://attacker.comに設定されます。

上記のケースでは、元のredirect_uriパラメータを無視し、適切な検証なしにreturnUrlという新しいパラメータを導入したExpo。この見落としは、攻撃者にFacebookから返されたAuthorization Codeにアクセスする機会を提供しました。詳細については、オリジナルの投稿を参照してください。

Redirect URIの検証は以下の重要な目的を果たします:

  1. フィッシング攻撃を防ぐ:Redirect URIを検証することで、認証サーバーはユーザーが信頼され、承認されたエンドポイントにリダイレクトされることを確認します。これにより、攻撃者がユーザーを悪意あるまたは未承認の場所にリダイレクトすることを防ぐのに役立ちます。
  2. オープンリダイレクトに対する保護:オープンリダイレクトは、ユーザーを悪意あるウェブサイトにリダイレクトするために悪用される脆弱性です。Redirect URIを検証することで、認証サーバーは、リダイレクトが認定のドメインまたは一連の信頼されるドメインの境界内に留まることを確認できます。
  3. 認可応答の正確なルーティングを確認する:Redirect URIを検証することは、認可応答、たとえばAuthorization CodeやAccess Tokenが正しい宛先に配信されることを保証するのに役立ちます。

Logtoでは、すべてのタイプのアプリケーションに対してredirect_uriの登録が必須です。私たちは、受け取った値を登録されたものと比較し、一致します。それには、カスタム検索パラメータも含まれます。認可リクエストが欠けている、無効な、または一致しないredirect_uri値の検証に失敗した場合、無効なRedirect URIエラーが登録されているredirect_uriに返されます。

まとめ

これらの詳細は複雑で微妙であるため、それらが見落とされることがよく理解できます。その中には、stateのようなランダムな文字列もあります。

しかし、重要なのは、これらのセキュリティ対策がユーザー認可に保護のレイヤーを追加し、CSRF攻撃、Authorization Code傍受、および無許可のリダイレクトなどのリスクを軽減することです。

これらは、OAuthプロトコルが提供する包括的なセキュリティ機能の一部に過ぎません。OAuthは安全な認証と認可のための堅牢なフレームワークを提供します。また、現実の製品アプリケーションで様々な要件を満たすための柔軟でオープンなエンドポイントも提供します。

開発者やサービスプロバイダーとして、ユーザー認証フローのセキュリティを常に優先することが不可欠です。警戒心を保ち、最善の規範を順守し、OAuthエコシステムの最新の開発を追い足すことは、ユーザーのアイデンティティと敏感なデータの矛盾と保護を確保するための必須です。私たちは、OAuthの実装における最高のセキュリティ基準の維持と、ユーザーのプライバシーと信頼の保護に引き続き専念することを確認します。