SpringSecurityによるユーザー名列挙攻撃の防止
1. 概要
このチュートリアルでは、一般的な列挙型攻撃について説明します。 具体的には、Webアプリケーションに対するユーザー名列挙攻撃について説明します。 そして、最も重要なのは、Springセキュリティを介してそれらを処理するためのオプションを検討することです。
2. 列挙型攻撃の説明
列挙とは、技術的には、コレクション内のすべてのアイテムの完全で順序付けられたリストを意味します。この定義は数学に限定されていますが、その本質により、強力なハッキングツールになります。 列挙は、悪用に使用できる攻撃ベクトルを公開することがよくあります。このコンテキストでは、リソース列挙と呼ばれることがよくあります。
リソースの列挙は、その名前が示すように、任意のホストからリソースのリストを収集する方法です。 これらのリソースは、ユーザー名、サービス、ページなど、価値のあるものであれば何でもかまいません。 これらのリソースは、ホストの潜在的な脆弱性を明らかにする可能性があります。
現在、これらの脆弱性を悪用するために、調査済みまたは未調査のいくつかの可能な方法があります。
3. Webアプリケーションでよく見られる列挙型攻撃
Webアプリケーションで最も頻繁に使用される列挙攻撃の1つは、ユーザー名列挙攻撃です。これは基本的に、Webアプリケーションの明示的または暗黙的な機能を使用して、有効なユーザー名を収集します。 攻撃者は、一般的なユーザー名の選択肢を使用してWebアプリケーションを攻撃する可能性があります。
さて、Webアプリケーションのどのような機能が、ユーザー名が有効かどうかを明らかにする可能性がありますか? 正直なところ、それは可能な限り変化させることができます。 これは、たとえば、ユーザー名が既に使用されていることをユーザーに通知する登録ページなど、設計された機能である可能性があります。
または、これは、有効なユーザー名を使用したログイン試行には、無効なユーザー名を使用したログイン試行とは大幅に異なる時間がかかるという事実と同じくらい暗黙的である可能性があります。
4. ユーザー名列挙攻撃をエミュレートするためのセットアップ
Spring BootおよびSpringセキュリティを使用する単純なユーザーWebアプリケーションを使用して、これらの攻撃ベクトルを示します。 このWebアプリケーションには、デモンストレーションをサポートするための最小限の機能セットがあります。 このようなアプリケーションのセットアップ方法の詳細については、前のチュートリアルで説明しています。
Webアプリケーションの一般的な機能により、列挙型攻撃を開始するために使用できる情報が明らかになることがよくあります。 それらを見ていきましょう。
4.1. ユーザー登録
ユーザー登録には一意のユーザー名が必要であり、簡単にするためにメールアドレスが選択されることがよくあります。 ここで、すでに存在する電子メールを選択した場合、アプリケーションはそのように通知する必要があります。
電子メールのリストを入手するのは難しくないという事実と相まって、これは、アプリケーションで有効なユーザー名を探し出すためのユーザー名列挙攻撃につながる可能性があります。
4.2. ユーザーログイン
同様に、アプリケーションにログインしようとすると、ユーザー名とパスワードを入力する必要があります。 これで、提供するユーザー名が存在しない場合、アプリケーションは次の情報を返す可能性があります。
これは、以前と同様に、ユーザー名列挙攻撃に利用できるほど単純です。
4.3. パスワードを再設定する
多くの場合、パスワードのリセットは、パスワードのリセットリンクをユーザーの電子メールに送信するために実装されます。 ここでも、ユーザー名または電子メールを提供する必要があります。
このユーザー名または電子メールがアプリケーションに存在しない場合、アプリケーションはそのように通知し、前に見たのと同様の脆弱性につながります。
5. ユーザー名列挙攻撃の防止
ユーザー名の列挙攻撃を防ぐには、いくつかの方法があります。 それらの多くは、Webアプリケーションのユーザーメッセージなどの機能を簡単に調整することで実現できます。
さらに、Spring Securityは時間の経過とともに成熟し、これらの攻撃ベクトルの多くの処理をサポートできるようになりました。 カスタムセーフガードを作成するための、すぐに使用できる機能と拡張ポイントがあります。 これらのテクニックのいくつかを探求します。
そのような攻撃を防ぐために利用できる人気のあるオプションを見てみましょう。 これらのソリューションのすべてがWebアプリケーションのすべての部分で適切または可能であるとは限らないことに注意してください。これについては、後で詳しく説明します。
5.1. メッセージの調整
まず、必要以上の情報を誤って提供する可能性をすべて排除する必要があります。 これは登録では困難ですが、ログインとパスワードのリセットページではかなり簡単です。
たとえば、ログインページのメッセージを簡単に抽象化できます。
パスワードリセットページのメッセージと同様の調整を行うことができます。
5.2. CAPTCHAを含む
メッセージの微調整は一部のページではうまく機能しますが、登録のようにそれを行うのが難しいページもあります。 このような場合、CAPTCHAと呼ばれる別のツールを使用できます。
さて、この時点で、列挙攻撃は、通過する可能性が非常に多いため、ロボットによるものである可能性が高いことに注意する価値があります。 したがって、人間またはロボットの存在を検出すると、攻撃を防ぐのに役立ちます。 CAPTCHAは、これを実現するための一般的な方法として機能します。
CAPTCHAサービスをWebアプリケーションに実装または統合する方法はいくつかあります。 これらのサービスの1つは、 reCAPTCHA by Googleであり、登録ページに簡単に統合できます。
5.3. レート制限
CAPTCHAは目的を十分に果たしますが、遅延を追加し、さらに重要なことに、正当なユーザーに不便をもたらします。 これは、ログインなどの頻繁に使用されるページにより関連性があります。
ログインなどの頻繁に使用されるページへのロボット攻撃を防ぐのに役立つ1つの手法は、レート制限です。 レート制限とは、特定のしきい値を超えてリソースが連続して試行されないようにすることです。
たとえば、ログインの試行が3回失敗した後、特定のIPからの要求を1日間ブロックできます。
SpringSecurityはこれを特に便利にします。
まず、 AuthenticationFailureBadCredentialsEventおよびAuthenticationSuccessEventのリスナーを定義します。これらのリスナーは、特定のIPからの失敗した試行の数を記録するサービスを呼び出します。 設定されたしきい値に違反すると、それ以降のリクエストはUserDetailsServiceでブロックされます。
このアプローチの詳細については、別のチュートリアルを参照してください。
5.4. 地理的制限
さらに、登録時にユーザーの国ごとの場所を取得できます。 これを使用して、別の場所からのログイン試行を確認できます。 異常な場所を検出した場合は、適切なアクションを実行できます。
- キャプチャを選択的に有効にする
- ステップアップ認証を実施する(多要素認証の一部として)
- ユーザーに場所を安全に確認するように依頼します
- 連続するリクエストでユーザーを一時的にブロックする
繰り返しになりますが、Spring Securityは、その拡張ポイントを介して、AuthenticationProviderにカスタムロケーション検証サービスをプラグインすることを可能にします。 これの特定のフレーバーは、前のチュートリアルで詳細に説明されています。
5.5. 多要素認証
最後に、パスワードベースの認証が最初であり、ほとんどの場合、必要な唯一のステップであることに注意する必要があります。 しかし、アプリケーションがセキュリティを強化するために多要素認証メカニズムを採用することは珍しくありません。 これは、オンラインバンキングのような機密性の高いアプリケーションに特に当てはまります。
多要素認証に関しては、多くの要因が考えられます。
- ナレッジファクター:これは、PINなどのユーザーが知っていることを指します
- 所有係数:これは、トークンやスマートフォンなど、ユーザーが所有するものを指します
- 固有の要因:これは、指紋など、ユーザーが本質的に持っているものを指します
Spring Securityは、カスタム AuthenticationProviderをプラグインできるため、ここでも非常に便利です。 Google Authenticatorアプリは、追加の所有要素を実装するための一般的な選択肢です。 これにより、ユーザーはスマートフォンのアプリでエフェメラルトークンを生成し、それを任意のアプリケーションでの認証に使用できます。 明らかに、これには、登録中または後で、アプリケーションで事前にユーザーを設定する必要があります。
SpringセキュリティアプリケーションへのGoogle認証システムの統合については、以前のチュートリアルで詳しく説明されています。
さらに重要なことに、多要素認証のようなソリューションは、アプリケーションがそれを必要とする場合にのみ適しています。 したがって、主に列挙型攻撃を防ぐために使用するべきではありません。
5.6. 処理時間の遅延
ログインのようにリクエストを処理している間、ユーザー名が存在するかどうかを確認することが、私たちが最初に行うことであることがよくあります。 ユーザー名が存在しない場合、リクエストはすぐにエラーで返されます。 逆に、有効なユーザー名を使用したリクエストには、パスワードの一致や役割の確認など、さらに多くの手順が必要になります。 当然、これらの両方のケースに対応する時間は異なる場合があります。
これで、ユーザー名が有効かどうかという事実を隠すためにエラーメッセージを抽象化しても、処理時間の大幅な違いが攻撃者をひっくり返す可能性があります。
この問題の考えられる解決策は、処理時間の違いを除外するために強制遅延を追加することです。 ただし、これは確実に発生する可能性のある問題ではないため、必要な場合にのみこのソリューションを採用する必要があります。
6. まとめ
ユーザー名列挙攻撃に関しては、使用する多くのトリックについて説明しましたが、いつ何を使用するかを尋ねるのは自然なことです。 明らかに、これに対する答えは1つではありません。これは、主にアプリケーションのタイプとその要件に基づいているためです。
ユーザーへのメッセージなど、いくつかのことは、可能な限り少ない情報を漏らさなければなりません。 さらに、ログインなどのリソースに対して連続して失敗する試行を制限することをお勧めします。
ただし、要件で必要と見なされる場合にのみ、追加の手段を使用する必要があります。 また、ユーザビリティへの抑止力と合理的に比較検討する必要があります。
さらに、これらの対策をさまざまなリソースに任意に組み合わせて適用し、それらを選択的に保護できることを理解することが重要です。
7. 結論
このチュートリアルでは、列挙型攻撃、特にユーザー名列挙型攻撃について説明しました。 これは、SpringSecurityを備えた単純なSpringBootアプリケーションのレンズを通して見ました。
ユーザー名列挙攻撃の懸念に段階的に対処するために、いくつかの方法を検討しました。
最後に、アプリケーションのセキュリティにおけるこれらの対策の適切性について説明しました。
いつものように、例のコードはGitHubでから入手できます。