サービス拒否(DoS)攻撃の緩和策#

クライアントがサーバーに過負荷をかけ、他のクライアントへのサービスを拒否する方法は複数あります。単純な例としては、サーバーのリソースが枯渇するほど高い頻度で負荷の高いルートを呼び出すことです。これは(ルートが人気がある場合)無害に発生する可能性がありますが、多くのクライアントリソースを消費するため、サーバーリソースを枯渇させる悪意のある方法も存在します。

ここでは、緩和策が講じられ、議論される2つの攻撃方法があります。1つ目は、サーバーへの接続を解放せずにできるだけ多くの接続を開き、最終的にすべての接続を使い果たし、他のクライアントの接続を妨げることを目的としています。ほとんどのリクエスト/レスポンスサイクルは、接続が閉じられるまでに数ミリ秒しかかからないため、重要なのは、何らかの方法で接続を開いたままにすることです。

2つ目は、サーバーのメモリを枯渇させ、サーバーの速度を著しく低下させるか、サーバーアプリケーションを強制終了させ、他のクライアントへのサーバーからの応答を妨げることを目的としています。ここで重要なのは、サーバーに大量の情報をメモリに書き込ませることです。

非アクティブな接続#

この攻撃は最初のタイプで、サーバーの接続を使い果たすことを目的としています。これは、サーバーへの接続を開き、その接続で何もせずに動作します。構成が不十分なサーバーは、クライアントが何かをするのを待機し、接続を開いたままにします。

この攻撃から保護するのはASGIサーバーの責任であり、通常は設定可能なキープアライブまたはタイムアウト設定を使用します。

大きなリクエストボディ#

この攻撃は2番目のタイプで、大きなリクエストボディを受信(したがってボディをメモリに書き込む)ことでサーバーのメモリを枯渇させることを目的としています。構成が不十分なサーバーでは、リクエストボディサイズに制限がなく、1つのリクエストでサーバーを枯渇させる可能性があります。

これを軽減するために、Quartはリクエストボディサイズをアプリケーション設定[‘MAX_CONTENT_LENGTH’]で設定された値に制限します。この制限を超えるボディを持つリクエストは、リクエストエンティティが大きすぎることを示す413エラー応答をトリガーします。

MAX_CONTENT_LENGTHのデフォルト値は16MBです。これは、Flaskドキュメントで議論されている制限であるため選択されました。

技術的には、この制限は、Quartがリクエストボディに対してメモリに許可する最大データ量を指します。これにより、必要に応じてより大きなボディを受信して使用できます。重要なのは、データが使用され、メモリに格納されないことです。例は以下のとおりです。

async def route():
    async for data in request.body:
        # Do something with the data
        ...

リクエストをストリーミングする場合は、各チャンク内にタイムアウトを追加することをお勧めします。

遅いリクエストボディ#

この攻撃は最初のタイプで、リクエストボディを長時間待つようにサーバーを誘導することで、サーバーの接続を使い果たすことを目的としています。構成が不十分なサーバーは、リクエストボディを無期限に待機します。

これを緩和するために、Quartはデフォルトではリクエストボディを待機せず、リクエストに正しい認証がない場合など、可能な場合はルートハンドラーが応答できるようにします。ボディが必要な場合、アプリケーション設定[‘BODY_TIMEOUT’]は、ボディが完全に受信されるのを待つ秒数を定義します。タイムアウトになると、QuartはRequestTimeout(408)で応答します。

デフォルト値は60秒です。これは、一般的なデフォルトのタイムアウト値であるため選択されました。

技術的には、タイムアウトはbody属性ではなく、応答データメソッド(get_data、data、json、get_json、form、およびfiles)にのみ適用されます。これにより、必要な場合に既知のストリーミングリクエストを使用できます。「リクエストボディの消費」を参照してください。

応答の非消費#

この攻撃は2番目のタイプで、クライアントに送信されたデータを使用しないことでサーバーのメモリを枯渇させることを目的としています。この失敗により、サーバーにバックプレッシャーが発生し、応答が接続ではなくメモリに書き込まれます。構成が不十分なサーバーはバックプレッシャーを無視し、メモリを枯渇させます。(これは、ビデオストリーミングなど、大量のデータを応答するルートが必要です)。

この攻撃から保護するのはASGIサーバーの責任です。

遅い応答の消費#

この攻撃は最初のタイプで、バックプレッシャーを無期限に適用するなど、応答の送信に長時間かかるようにサーバーを誘導することで、サーバーの接続を使い果たすことを目的としています。構成が不十分なサーバーは、応答を送信しようとして無期限に待機します。

これを緩和するために、Quartは応答の送信を試行する時間を、アプリケーション設定[‘RESPONSE_TIMEOUT’]で設定された時間に制限します。この時間が経過すると、接続は突然閉じられます。

デフォルト値は60秒です。これは、一般的なデフォルトのタイムアウト値であるため選択されました。

技術的には、この制限は、たとえば大きなファイルを返す単一のルートがある場合など、必要に応じて応答ごとに構成できます。これは、その例です。

async def route():
    response = await make_response(...)
    response.timeout = 120
    return response

大きなwebsocketメッセージ#

この攻撃は2番目のタイプで、非常に大きなWebSocketメッセージを受信させることでサーバーのメモリを枯渇させることを目的としています。構成が不十分なサーバーでは、メッセージサイズに制限がなく、1つのメッセージでサーバーを枯渇させる可能性があります。

この攻撃から保護するのはASGIサーバーの責任です。