Securing Your Web APIs: Understanding and Implementing IP Based Rate Limiting in .NET Core

Securing Your Web APIs: Understanding and Implementing IP Based Rate Limiting in .NET Core

Rate limiting is a technique employed in computer systems, particularly in web applications and APIs, to control and restrict the rate at which incoming requests are processed or served. The primary purpose of rate limiting is to prevent abuse, protect system resources, and ensure fair and equitable access to services for all users.

In essence, rate limiting sets predefined thresholds or limits on the number of requests a client or user can make within a specified time interval. When these limits are exceeded, the system responds by delaying, rejecting, or otherwise controlling the processing of additional requests, mitigating the risk of overuse, denial-of-service attacks, or unintended resource consumption.

Types of rate limiting

  • IP-based Rate Limiting:

    IP-based rate limiting is a method of controlling access to a web application or API by restricting the number of requests from a specific IP address within a defined time frame. This approach is particularly effective in mitigating potential threats and preventing abuse by limiting the rate at which a single IP address can make requests to the server.

  • Client-based Rate Limiting:

    Client-based rate limiting is a method used to control and manage access to a web application or API by restricting the number of requests from a specific client or user within a specified time interval. Unlike IP-based rate limiting, which relies on the source IP address, client-based rate limiting focuses on identifying and managing individual clients or users based on their unique credentials.

  • Token Bucket Algorithm:

    The Token Bucket Algorithm is a commonly used method for implementing rate limiting in computer systems, including web applications. It provides a simple yet effective way to control the rate at which requests are processed over time.

Setting Up IP Rate Limiting in .NET Core using Nuget Package

A. Installing Necessary Packages:

  1. Open your .NET Core project in Visual Studio or your preferred code editor.

  2. In the Package Manager Console or the terminal, install the required NuGet package for rate limiting. For example, using the "AspNetCoreRateLimit" package:

     bashCopy codedotnet add package AspNetCoreRateLimit
    
  3. Restore the project to apply the changes:

     bashCopy codedotnet restore
    

B. Configuration Settings:

  1. Open your appsettings.json file to configure rate-limiting settings. Define rate limits based on your application's requirements. Here's an example configuration:

     jsonCopy code"IpRateLimiting": {
       "EnableEndpointRateLimiting": true,
       "StackBlockedRequests": false,
       "RealIpHeader": "X-Real-IP",
       "ClientIdHeader": "X-ClientId",
       "HttpStatusCode": 429,
       "GeneralRules": [
         {
           "Endpoint": "*",
           "Period": "1s",
           "Limit": 5
         },
         {
           "Endpoint": "api/values",
           "Period": "1m",
           "Limit": 10
         }
       ]
     }
    
    • EnableEndpointRateLimiting: Enable or disable endpoint-specific rate limiting.

    • StackBlockedRequests: Whether to stack blocked requests or reject immediately.

    • RealIpHeader and ClientIdHeader: Headers to identify the real IP and client ID (customize as needed).

    • HttpStatusCode: HTTP status code to return when a request is blocked.

    • GeneralRules: Define rate limit rules for specific endpoints.

C. Middleware Configuration:

  1. In your Startup.cs file, configure the rate-limiting middleware. Add the following code in the ConfigureServices method:
services.AddMemoryCache();
services.Configure<IpRateLimitOptions>(Configuration.GetSection("IpRateLimiting"));
services.AddIpRateLimiting();
  1. In the Configure method, add the middleware to the pipeline:
app.UseIpRateLimiting();

Testing and Monitoring:

  1. Test rate limiting by sending requests to your endpoints and observing the behavior when rate limits are exceeded.

  2. Monitor rate-limiting metrics using tools like logs, performance monitoring, or specialized rate-limiting monitoring tools.

Custom IP Rate Limiting Middleware in .NET Core

using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Caching.Memory;
using System;
using System.Threading.Tasks;

public class RateLimitMiddleware
{
    private readonly RequestDelegate _next;
    private readonly int _limit;
    private readonly TimeSpan _window;
    private readonly IMemoryCache _cache;

    public RateLimitMiddleware(RequestDelegate next, int limit, TimeSpan window, IMemoryCache cache)
    {
        _next = next ?? throw new ArgumentNullException(nameof(next));
        _limit = limit;
        _window = window;
        _cache = cache ?? throw new ArgumentNullException(nameof(cache));
    }

    public async Task Invoke(HttpContext context)
    {
        var ipAddress = context.Connection.RemoteIpAddress.ToString();
        var cacheKey = $"{ipAddress}_RequestCount";

        if (!_cache.TryGetValue(cacheKey, out int requestCount))
        {
            requestCount = 0;
        }

        if (requestCount >= _limit)
        {
            context.Response.StatusCode = 429; // Too Many Requests
            await context.Response.WriteAsync("Rate limit exceeded.");
            return;
        }

        _cache.Set(cacheKey, requestCount + 1, _window);

        await _next(context);
    }
}

public static class RateLimitMiddlewareExtensions
{
    public static IApplicationBuilder UseRateLimiting(this IApplicationBuilder builder, int limit, TimeSpan window)
    {
        return builder.UseMiddleware<RateLimitMiddleware>(limit, window);
    }
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    // other middleware configurations

    app.UseRateLimiting(limit: 100, window: TimeSpan.FromMinutes(1));

    // more middleware configurations
}

In this example, the RateLimitMiddleware checks the number of requests from a specific IP address within a specified time window using the IMemoryCache. If the limit is exceeded, it returns a 429 status code; otherwise, it allows the request to proceed