logo

Symmetric denial of service - Dart


Need

Prevention of service outages caused by repeated resource-intensive requests


Context

  1. Usage of Dart 2.0 for developing cross-platform applications
  2. Usage of Shelf for ORM (Object-Relational Mapping) in Node.js
  3. 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

  1. Identify the resource-intensive operations in your code. In this case, it's the loop that prints numbers from 0 to 100000000.
  2. 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.
  3. Consider using asynchronous programming to prevent blocking operations. This allows the server to handle other requests while the resource-intensive operation is being processed.
  4. Optimize the resource-intensive operation. In this case, the loop that prints numbers could be removed or replaced with a less resource-intensive operation.
  5. 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

  • 003 - Symmetric denial of service

  • Last updated

    2023/09/18