[C# web API]webサービスを守る仕組み・レートリミットを導入してみる

レートリミットってご存知ですか?
いろいろ言い方はあるかもしれませんが、

「指定期間内に実行できるリクエスト数の制限」

という風に捉えています。

今回、webサービスにてレートリミットを実装したのでメモ。尚要件として、
・ログインしていない場合はCookieベース
・ログインしていたらログインIDベース
で端末を識別するようにしています。

本来ここに「ログイン試行回数は5分間に5回まで(ログインしたらリセット)」や、「パスワード再発行リクエストは1時間に5回まで」みたいな個別のパターンも必要でしょうが、ここでは省きます。

実際のコード

まず、.NET7以上が前提の書き方です。7以上の場合、純正の仕組みが使えます。

Program.csを開き、usingを追加。

using System.Threading.RateLimiting;

もうそのままの名前ですね。

そしてProgram.csにて、builderへの記述と呼び出しの二箇所を追加。

...

builder.Services.AddRateLimiter(options =>
{
  options.AddPolicy("ratelimit-policy", httpContext =>
    {
        ...ログイン済みか判定するためにユーザ情報を取得する処理を記述。(プロジェクト依存)
        var userId = ---;
        if (!string.IsNullOrEmpty(userId))
        {
            return RateLimitPartition.GetFixedWindowLimiter(userId, key =>
                new FixedWindowRateLimiterOptions
                {
                    PermitLimit = 100,
                    Window = TimeSpan.FromMinutes(1) //直近1分間で100回までOKの意
                }            
            );
        }
        else
        {
            // 未認証の場合、クッキーを使って検証する
            var cookieId = httpContext.Request.Cookies["deviceId"];
            if (string.IsNullOrEmpty(cookieId))
            {
                // クッキーが存在しない場合、新しいIDを生成してクッキーにセット
                cookieId = Guid.NewGuid().ToString();
                httpContext.Response.Cookies.Append("deviceId", cookieId);
            }

            return RateLimitPartition.GetFixedWindowLimiter(cookieId, key =>
                new FixedWindowRateLimiterOptions
                {
                    PermitLimit = 100,
                    Window = TimeSpan.FromMinutes(1)
                }            
            );
        }
    });

    // ブロック時のステータスコード
    options.RejectionStatusCode = 429;
});

--Buildする前に記述。
var app = builder.Build();


...

app.UseAuthorization();
--認証ポリシーの後に記述
app.UseRateLimiter(); 
...

そしてコントローラにてポリシーを適用します。

[EnableRateLimiting("ratelimit-policy")]
public class HogeController : ControllerBase
...

試しにリミット値を厳しめにして、対象URLにブラウザリロードやSwaggerでアクセスしてみてください。

まとめ

公式が対応してくれただけあって簡単ですね。ただこれだけでは足りないところもありますので、自身の開発するサービスと照らし合わせて、どこに個別対応が必要か考えてください。

コメント

タイトルとURLをコピーしました