DDoS Attacks and Prevention using .NET Core

In this article, we will learn about DDoS attacks and their prevention using .NET core.

What is a DDoS (Distributed Denial of Service (DDoS) attack?

DDoS

Image credit

When there are millions of requests to a particular server or set of servers, the server becomes too busy to serve the request, in other words, making server overload via sending false or malicious requests. The result of this attack is to make the server unavailable to serve requests or server unavailable.

A DDoS attack aims to disable or take down a website, web application, cloud service, or other online resource by overwhelming it with pointless connection requests, fake packets, or other malicious traffic.

How do you identify if the Server is having such an attack?

A symptom of a DDoS attack is a site or service suddenly becoming slow or unavailable, in this case, further investigation is required to see if there is suspicious traffic or web server has genuine traffic.

  • It is required to check logs and traffic analytic tools, which can be used to see the IP address of sources.
  • If traffic originates from a single IP address or IP range, then this must be DDoS.
  • Odd traffic patterns, such as spikes at odd hours of the day or patterns that appear to be unnatural (e.g., a spike every 10 minutes).

Solution

1. Prevention Technique. Rate Limiter

At the application level, if we want to restrict traffic to an application, we can use Rate Limiter in the .NET core.

In this example, we will configure our service to accept only 20 requests per second, and after that, it will reject or accept any requests.

Steps

Create Web api .net core project.

Web API

This is the default template and contains a Weather controller.

Program .cs -> Add the below code.

builder.Services.AddRateLimiter(options => 
{
    options.GlobalLimiter = PartitionedRateLimiter.Create<HttpContext, string>(
        httpContext => RateLimitPartition.GetFixedWindowLimiter(
            partitionKey: httpContext.User.Identity?.Name ?? httpContext.Request.Headers.Host.ToString(), 
            factory: partition => new FixedWindowRateLimiterOptions
            {
                AutoReplenishment = true,
                PermitLimit = 20,
                QueueLimit = 0,
                Window = TimeSpan.FromMinutes(1)
            }
        )
    );
});
var app = builder.Build();
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
    app.UseSwagger();
    app.UseSwaggerUI();
}
app.UseHttpsRedirection();
app.UseAuthorization();
app.UseRateLimiter();
app.MapControllers();
app.Run();

builder.Services.AddRateLimiter

The method is used to configure and register the rate limiter service with the application’s service container. Once added to the application, the rate limiter can be used to control access to certain routes or endpoints, ensuring that they are not overwhelmed by too many requests.

Now, if we want to set a global rate limiter for all requests, the GlobalLimiter option is set to any PartitionedRateLimiter. In the above example, we have added a FixedWindowLimiter and configured it to apply “per authenticated username (or hostname if not authenticated)” - to the partition. The FixedWindowLimiter is then configured to automatically replenish permitted requests and permits 20 requests per minute.

Testing

I have created a console application that makes http requests to weather API.

// See https://aka.ms/new-console-template for more information
using System.Text.Json;
Console.WriteLine("Making connections....!");
var apiUrl = "https://localhost:44316/WeatherForecast"; // Example API endpoint
using var client = new HttpClient();
try
{
    for (int i = 0; i < 21; i++)
    {
        // Making the GET request
        var response = await client.GetAsync(apiUrl);
        // Ensure the request was successful
        response.EnsureSuccessStatusCode();
        // Read the response content as a string
        var content = await response.Content.ReadAsStringAsync();
        if (content != null && content.Length > 0)
        {
            Console.WriteLine("Getting response from server -> " + i.ToString());
        }
    }
}
catch (Exception e)
{
    Console.WriteLine($"Request error: {e.Message}");
    Console.ReadKey();
}
  1. The above code contains a loop for making api calls for 21 times.
  2. We are logging Console.WriteLine(“Getting response from server ->” + i.ToString());

The above code is making http calls api.

var apiUrl = "https://localhost:44316/WeatherForecast"; // Example API endpoint

Running the application.

  • API
    API
  • Console: we can see requests are getting responses till 19 and get exceptions after 19.
    Console
  • Specific error code: we can add the code below and get specific exceptions.
    options.RejectionStatusCode = 429;
    
    Error Code
  • We have multiple ways to implement rate limiters and have the below types, but I will be explaining them in a separate article.
    Rate limiter

2. Prevention Technique. IP Blocking and Geo-Blocking

If we know the range of IPs from where we are getting attacks, we can restrict specific IP addresses. We can use the below approach in the .net core.

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    app.Use(async (context, next) =>
    {
        var ipAddress = context.Connection.RemoteIpAddress.ToString();
        if (ipAddress == "blocked_ip")
        {
            context.Response.StatusCode = 403;
            await context.Response.WriteAsync("Forbidden");
        }
        else
        {
            await next.Invoke();
        }
    });
    app.UseMvc();
}

3. Prevention Technique. Monitoring and Alerting

  • We should keep tracing logs using Application Insights to see if we have a lot of requests coming from suspicious IPs.
  • Set up alerts for unusual traffic patterns.

4. Prevention Technique. Throttling and Circuit Breaker Patterns

  • Implement throttling to control the usage of resources.
  • Use libraries like Polly for resilience and transient fault handling.
var circuitBreaker = Policy
    .Handle<Exception>()
    .CircuitBreakerAsync(2, TimeSpan.FromMinutes(1));

5. Prevention Technique. Caching

DDoS can also happen in the case of real traffic, in the case of e-commerce sites like Flipkart, Amazon has huge traffic during the sale and if we keep posting a request to servers then servers can be busy resulting in DDoS.

In this case, we can at least apply cache for frequently used data or data from master tables we can limit the number of requests to the server.

public void ConfigureServices(IServiceCollection services)
{
    services.AddResponseCaching();
    services.AddMvc();
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    app.UseResponseCaching();
    app.UseMvc();
}
[HttpGet]
[ResponseCache(Duration = 60)]
public IActionResult Get()
{
    return Ok("This response is cached for 60 seconds.");
}

6. Prevention Technique. Network Level, Load Balancers, and Firewall's

DDoS can also happen in the case of real traffic, in the case of e-commerce sites like Flipkart, Amazon has huge traffic during sales and if we keep posting requests to servers then servers can be busy resulting in DDoS.

We can use Azure Load Balancer or AWS Elastic Load Balancing (ELB) to distribute load to multiple servers.

In case of false traffic or malicious traffic, we can implement rules at the network level. Here, we can add rules that can filter the range of IPs and also divert IP addresses to multiple servers.

Network Level

Conclusion

We have covered what DDoS is and the multiple ways to prevent it.

Thanks!