OAuth 2.0の状態パラメーターを使って攻撃を防ぎ、ユーザーをリダイレクトする

認可プロトコルはstateパラメーターを提供して、アプリケーションを以前の状態に復元できるようにします。stateパラメーターは、クライアントが認可要求で設定した状態オブジェクトの一部を保持して、応答でクライアントが使用できるようにします。

CSRF攻撃

stateパラメーターを使用する主な理由は、まもなく開始される各認証要求に関連付けられた、推測できない一意の値を使用することで、CSRF攻撃を軽減することにあります。攻撃を防ぐために、受信する応答が送信した値と一致していることを確認できます。

stateパラメーターは文字列なので、それに他のあらゆる情報をエンコードすることができます。認証要求の開始時にランダムな値を送信して、応答を処理する際に受け取った値を検証します。クライアントアプリケーション側(Cookie、セッション、ローカルストレージ)に、検証を可能にする何かを保管します。状態が一致しない応答を受け取った場合には、受信者側が望んでいない要求に対する応答か、応答を偽造しようとしていることになるため、攻撃の標的になっているかもしれないと推測することができます。

CSRF攻撃では、偽の要求に対する応答を知る手段が攻撃者にないため、ユーザーデータの取得ではなく、状態変更要求に的を絞って攻撃し、操作を仕掛けようとします。基本的に、状態パラメーターはnonceとなり、要求と認証からの応答を関係付けるのに使用されます。

最新のOIDCとOAuth SDKでは、シングルページアプリケーションにAuth0.jsが含まれており、状態の生成と検証が自動的に処理されます。

状態パラメーターに値を設定して比較する

  1. IDプロバイダー(IdP)に要求をリダイレクトする前に、アプリを使ってランダムな文字列を生成します。例:

    xyzABC123

    Was this helpful?

    /
    状態の長さは無限ではありません。414 Request-URI Too Largeエラーが表示された場合は、より小さい値を試してください。

  2. 文字列をローカルに保管します。例:

    storeStateLocally(xyzABC123)

    Was this helpful?

    /

  3. stateパラメーターを要求(必要な場合はURLエンコード)に追加します。例:

    // Encode the String   
    tenant.auth0.com/authorize?...&state=xyzABC123

    Was this helpful?

    /
    要求を送信すると、Auth0がユーザーをアプリケーションにリダイレクトで戻します。state値が含まれています。使用している接続の種類に応じて、この値が要求のボディか、クエリ文字列に挿入されます。
    /callback?...&state=xyzABC123

    Was this helpful?

    /

  4. 返されたstate値を取得して、保管してある値と比較します。値が一致した場合には認証要求が承認され、一致しない場合には拒否されます。

    // Decode the String
    var decodedString = Base64.decode(encodedString);
    if(receivedState === retrieveStateStoredLocally()) {
     // Authorized request
    } 
    else {
      // This response is not for us, reject it
    }

    Was this helpful?

    /

ユーザーをリダイレクトする

stateパラメーターを使用すると、アプリケーションの状態として、認証処理が開始する前にユーザーがいた場所をエンコードすることができます。たとえば、アプリケーションでユーザーが保護されたページにアクセスしようとして、その操作が認証要求のトリガーとなった場合には、そのURLを保管し、認証の完了後にユーザーをその意図したページにリダイレクトで戻すことができます。

nonceを生成して、リダイレクトURLなどの必要な状態データと共に、ローカル(Cookieやセッション、ローカルストレージ)に保管します。nonceをプロトコルメッセージで状態として使用します。返された状態が保管しているnonceと一致する場合には、OAuth2メッセージを受け入れて、対応するデータをストレージから取得します。これが、auth0.jsで使用されている方法になります。

保管されているURLを使ってユーザーをリダイレクトする

  1. nonceの状態パラメーターに値を設定して、上記で説明したようにCSRF攻撃を軽減できるようにします。

  2. nonceをローカルに保管して、ユーザーがアクセスしたいURLなど、他のアプリケーションの状態情報を保管するためのキーとして使用します。例:

    {
      "xyzABC123" : {
        redirectUrl: '/protectedResource',
        expiresOn: [...]
      }
    }

    Was this helpful?

    /

  3. ユーザーを認証し、生成したnonceを状態として送信します

  4. コールバック処理と応答検証の一環として、返された状態が保管しているnonceと一致するかを検証します。一致する場合には、残りのアプリケーションの状態(redirectUrlなど)を取得します。

  5. コールバック処理が完了したら、保管してあったURLにユーザーをリダイレクトします。

代替のリダイレクト方法

  1. nonceの値を生成して、ローカルに保管します。

  2. nonceを必要な状態(リダイレクトURLなど)データと共に保護されたメッセージ(改ざんを防ぐために暗号化と署名が必要)内でエンコードします。

  3. 応答処理で、メッセージの保護を解除して、nonceと他のプロパティを保管します。

  4. 含まれているnonceがローカルに保管しているnonceと一致するかを検証し、一致する場合にはOAuth2メッセージを受け入れます。

制限と考慮事項

  • 保管する方法はアプリケーションの種類に基づいて選択してください。

    アプリタイプ 推奨ストレージ
    通常のWebアプリ クッキーまたはセッション
    SPA ローカルブラウザー
    ネイティブアプリ メモリまたはローカル

  • セキュリティの観点からすれば、要求も応答も整合性が保護されたものではないため、ユーザーの操作が可能です。これは、パラメーターをredirect_uriに追加する場合も同様です。

  • 状態パラメーター値の長さは無限ではありません。414 Request-URI Too Largeエラーが表示された場合は、より小さい値を試してください。

  • URLをプレーンテキストや他の推測可能な方法で渡すのは危険です。状態パラメーターの値については、以下を必ず守ってください。

    • CSRF攻撃やフィッシング攻撃からの防御に使えるように、一意で不透明なものにします。

    • Cookieに保管する場合には、改ざんを防ぐために必ず署名します。

もっと詳しく