Symmetric denial of service - Dart
Need
Prevention of service outages caused by repeated resource-intensive requests
Context
- Usage of Dart 2.0 for developing cross-platform applications
- Usage of Shelf for ORM (Object-Relational Mapping) in Node.js
- Usage of shelf_io for managing data storage and retrieval
Description
Insecure Code Example
import 'package:shelf/shelf.dart' as shelf;
import 'package:shelf/shelf_io.dart' as io;
void main() {
var handler = const shelf.Pipeline().addMiddleware(shelf.logRequests())
.addHandler(_echoRequest);
io.serve(handler, 'localhost', 8080);
}
shelf.Response _echoRequest(shelf.Request request) {
// This is a resource-intensive operation
for (int i = 0; i < 100000000; i++) {
print(i);
}
return shelf.Response.ok('Request processed.');
}
The above Dart code represents a simple server application using the `shelf` framework. The application listens to requests on port 8080 and processes them using the `_echoRequest` function. The vulnerability lies in the `_echoRequest` function where a resource-intensive operation is performed. In this case, the function runs a loop for 100,000,000 iterations and prints each iteration to the console. This operation consumes a lot of system resources and takes a considerable amount of time to complete. If an attacker repeatedly sends requests to the server, each request will trigger this resource-intensive operation. As a result, the server will be overwhelmed with the processing of these requests and will become unresponsive. This is known as a Symmetric Denial of Service (DoS) vulnerability.
Steps
- Identify the resource-intensive operations in your code. In this case, it's the loop that prints numbers from 0 to 100000000.
- Implement rate limiting to prevent a single client from making too many requests in a short period of time. This can be done using middleware in the server.
- Consider using asynchronous programming to prevent blocking operations. This allows the server to handle other requests while the resource-intensive operation is being processed.
- Optimize the resource-intensive operation. In this case, the loop that prints numbers could be removed or replaced with a less resource-intensive operation.
- Implement monitoring and logging to detect unusual activity or repeated requests from a single client. This can help identify potential denial of service attacks.
Secure Code Example
import 'dart:async';
import 'package:shelf/shelf.dart' as shelf;
import 'package:shelf/shelf_io.dart' as io;
import 'package:shelf_rate_limiter/shelf_rate_limiter.dart';
void main() {
var handler = const shelf.Pipeline()
.addMiddleware(shelf.logRequests())
.addMiddleware(rateLimiterMiddleware(maxOperationsPerPeriod: 5, period: Duration(seconds: 10)))
.addHandler(_echoRequest);
io.serve(handler, 'localhost', 8080);
}
Future<shelf.Response> _echoRequest(shelf.Request request) async {
// This is a resource-intensive operation
await Future.delayed(Duration(seconds: 2)); // Simulate delay
return shelf.Response.ok('Request processed.');
}
The updated code includes several changes to mitigate the risk of a symmetric denial of service attack. 1. **Rate Limiting**: We've added a rate limiter middleware to the server pipeline. This middleware limits the number of requests a client can make in a given period. In this case, a client can make a maximum of 5 requests every 10 seconds. This prevents a single client from overwhelming the server with too many requests. 2. **Asynchronous Programming**: The `_echoRequest` function has been updated to be an asynchronous function. This means that it returns a `Future`, which allows the server to handle other requests while it's waiting for the resource-intensive operation to complete. In this case, we've simulated a delay with `Future.delayed`, but in a real-world scenario, this could be a database query, file operation, or other time-consuming task. 3. **Optimization**: The resource-intensive operation (a loop that prints numbers from 0 to 100000000) has been removed. In a real-world scenario, you would need to identify and optimize any operations that consume a lot of resources or take a long time to complete. 4. **Monitoring and Logging**: The server uses the `logRequests` middleware to log all incoming requests. This can help you detect unusual activity or repeated requests from a single client, which could indicate a potential denial of service attack.
References
Last updated
2023/09/18