Denial Of Service in Aspnet with Cockroachdb
Denial Of Service in Aspnet with Cockroachdb — how this specific combination creates or exposes the vulnerability
A Denial of Service (DoS) scenario in an ASP.NET application using CockroachDB typically arises from resource exhaustion patterns in application logic and database interaction. When an ASP.NET endpoint executes long-running or unbounded database queries against CockroachDB without proper constraints, the thread pool on the web server can saturate. Saturated thread pools prevent new legitimate requests from being processed, effectively creating a service outage for users.
CockroachDB, while resilient to node failures, does not prevent poorly constructed queries from consuming significant compute and I/O on the database side. For example, an endpoint that executes a non-paginated SELECT * FROM orders without server-side limits can return very large result sets. Materializing large result sets in ASP.NET consumes memory and CPU, and if many concurrent requests perform similar operations, the application may exhaust available memory or connection pool quotas, triggering timeouts for all users.
Another specific risk arises from retry logic combined with CockroachDB’s transaction model. ASP.NET applications using Entity Framework Core or raw SQLClient may implement retries for transient errors. If a high-contention workload causes repeated transaction aborts, aggressive retries without exponential backoff can amplify request volume. This amplified load increases latency for all requests and can lead to thread pool starvation or connection pool exhaustion, manifesting as a DoS condition for the API.
Additionally, unbounded concurrency in asynchronous controller actions can overload CockroachDB. If an ASP.NET action method launches many concurrent database operations without limiting concurrency, the database may hit connection or statement concurrency limits. The resulting queuing and timeouts at the database layer propagate back to HTTP clients as 502 or 504 errors, effectively denying service.
These combinations highlight the importance of validating inputs, applying timeouts, and constraining concurrency at both the application and database layers to prevent DoS in ASP.NET services backed by CockroachDB.
Cockroachdb-Specific Remediation in Aspnet — concrete code fixes
Remediation focuses on query constraints, timeouts, and controlled concurrency. Use pagination, command timeouts, and explicit concurrency limits to reduce pressure on CockroachDB and the ASP.NET runtime.
1. Paginated queries with explicit limits
Always bound result sizes and use keyset pagination for large datasets. This prevents unbounded memory and network usage in ASP.NET.
// Example using Dapper with parameterized pagination
using System.Data;
using Dapper;
using Npgsql;
public async Task<IEnumerable<Order>> GetOrdersPagedAsync(string tenantId, int pageNumber = 1, int pageSize = 20)
{
await using var conn = new NpgsqlConnection("Host=localhost;Database=mydb;Username=appuser;SSL Mode=Require");
var offset = (pageNumber - 1) * pageSize;
var sql = @"
SELECT id, customer_id, total, created_at
FROM orders
WHERE tenant_id = @TenantId
ORDER BY created_at DESC
LIMIT @PageSize
OFFSET @Offset
";
return await conn.QueryAsync<Order>(sql, new { TenantId = tenantId, PageSize = pageSize, Offset = offset });
}
2. Configure command timeouts and cancellation
Set explicit command timeouts and support request-scoped cancellation to prevent hanging queries from tying up threads.
using System;
using System.Data;
using Dapper;
using Npgsql;
using System.Threading;
using System.Threading.Tasks;
public async Task<Order> GetOrderWithTimeoutAsync(Guid orderId, CancellationToken ct)
{
await using var conn = new NpgsqlConnection("Host=localhost;Database=mydb;Username=appuser;SSL Mode=Require");
const string sql = "SELECT id, customer_id, total, created_at FROM orders WHERE id = @Id";
var sqlCommand = new CommandDefinition(sql, new { Id = orderId }, cancellationToken: ct, commandTimeout: 10);
return await conn.QuerySingleOrDefaultAsync<Order>(sqlCommand);
}
3. Limit concurrency with SemaphoreSlim
Control the number of concurrent database operations to avoid overwhelming CockroachDB connections.
using System.Collections.Concurrent;
using System.Threading;
using System.Threading.Tasks;
public class OrderService
{
private static readonly SemaphoreSlim _throttle = new SemaphoreSlim(initialCount: 50, maxCount: 50);
public async Task<Order> GetOrderBoundedAsync(Guid orderId, CancellationToken ct)
{
await _throttle.WaitAsync(ct);
try
{
await using var conn = new NpgsqlConnection("Host=localhost;Database=mydb;Username=appuser;SSL Mode=Require");
const string sql = "SELECT id, customer_id, total, created_at FROM orders WHERE id = @Id";
return await conn.QuerySingleOrDefaultAsync<Order>(sql, new { Id = orderId }, cancellationToken: ct);
}
finally
{
_throttle.Release();
}
}
}
4. Avoid aggressive retry without backoff
Use Polly with incremental backoff and jitter, and cap retries to prevent amplification under contention.
using Polly;
using Polly.Retry;
using Npgsql;
using System.Net;
var retryPolicy = Policy
.Handle<PostgresException>(ex => ex.SqlState == "40001" || ex.SqlState == "55P03")
.WaitAndRetryAsync(
retryCount: 3,
sleepDurationProvider: attempt => TimeSpan.FromSeconds(Math.Pow(2, attempt)) + TimeSpan.FromMilliseconds(new Random().Next(0, 100)),
onRetry: (ex, timeSpan, context) => { /* log */ });
await retryPolicy.ExecuteAsync(async () =>
{
await using var conn = new NpgsqlConnection("Host=localhost;Database=mydb;Username=appuser;SSL Mode=Require");
await conn.OpenAsync();
using var cmd = new NpgsqlCommand("UPDATE orders SET total = @total WHERE id = @id", conn);
cmd.Parameters.AddWithValue("id", Guid.NewGuid());
cmd.Parameters.AddWithValue("total", 99.99);
await cmd.ExecuteNonQueryAsync();
});
5. Enforce request timeouts at the ASP.NET pipeline
Use cancellation tokens and configure Kestrel/application timeouts to bound request lifetime.
// In Program.cs or Startup.cs
builder.Services.Configure<KestrelServerOptions>(options =>
{
options.Limits.KeepAliveTimeout = TimeSpan.FromSeconds(30);
options.Limits.RequestHeadersTimeout = TimeSpan.FromSeconds(30);
});
builder.Services.Configure<IISServerOptions>(options =>
{
options.MaxRequestBodySize = 10_000_000;
});
Related CWEs: resourceConsumption
| CWE ID | Name | Severity |
|---|---|---|
| CWE-400 | Uncontrolled Resource Consumption | HIGH |
| CWE-770 | Allocation of Resources Without Limits | MEDIUM |
| CWE-799 | Improper Control of Interaction Frequency | MEDIUM |
| CWE-835 | Infinite Loop | HIGH |
| CWE-1050 | Excessive Platform Resource Consumption | MEDIUM |