logo

Data uniqueness not properly verified - Dart


Need

Enforcement of data uniqueness verification


Context

  1. Usage of Dart for building cross-platform mobile, web, and desktop applications
  2. Usage of Shelf for managing and organizing data in Node.js applications
  3. Usage of shelf_io for managing I/O operations in a Node.js application

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) {
  final String data = request.headers['data'];
  // Vulnerability: No verification of data uniqueness
  return shelf.Response.ok('You sent: $data');
}

The above Dart code is a simple server application using the Shelf framework. It listens on port 8080 and responds to any incoming request by echoing back the 'data' header from the request. The vulnerability lies in the `_echoRequest` function. This function takes the incoming request and directly uses the 'data' from the request headers without validating its uniqueness. This means that if an attacker were to reuse or regenerate the same 'data', the server would accept it as valid even though it should only be valid for one use. This could potentially lead to various security issues such as replay attacks, where an attacker could resend a previously sent request to perform an action without the user's consent. It could also lead to data integrity issues as the same 'data' could be used in different contexts, potentially leading to incorrect operations or results.

Steps

  1. Create a data structure, such as a set or a hash table, to store the data received from each request.
  2. Before processing a request, check if the data from the request already exists in the data structure.
  3. If the data already exists, return an error response indicating that the data is not unique.
  4. If the data does not exist in the data structure, add it to the data structure and proceed with processing the request.
  5. Ensure that the data structure is thread-safe if the application is multi-threaded.

Secure Code Example

import 'package:shelf/shelf.dart' as shelf;
import 'package:shelf/shelf_io.dart' as io;

// Create a Set to store the data from each request
final Set<String> dataSet = {};

void main() {
  var handler = const shelf.Pipeline().addMiddleware(shelf.logRequests())
      .addHandler(_echoRequest);

  io.serve(handler, 'localhost', 8080);
}

shelf.Response _echoRequest(shelf.Request request) {
  final String data = request.headers['data'];

  // Check if the data from the request already exists in the Set
  if (dataSet.contains(data)) {
    // If the data already exists, return an error response
    return shelf.Response(400, body: 'Error: Data is not unique');
  } else {
    // If the data does not exist in the Set, add it to the Set
    dataSet.add(data);
    return shelf.Response.ok('You sent: $data');
  }
}

The updated code fixes the vulnerability by properly validating the uniqueness of the data. A `Set` named `dataSet` is created to store the data received from each request. The `Set` data structure is used because it does not allow duplicate values, which makes it perfect for ensuring data uniqueness. In the `_echoRequest` function, before processing a request, the code checks if the data from the request already exists in the `dataSet`. This is done using the `contains` method of the `Set` class, which returns `true` if the element is found in the set, and `false` otherwise. If the `contains` method returns `true`, meaning the data already exists in the `dataSet`, the function returns an error response with a status code of `400` and a body of `'Error: Data is not unique'`. If the `contains` method returns `false`, meaning the data does not exist in the `dataSet`, the data is added to the `dataSet` using the `add` method of the `Set` class, and the function proceeds with processing the request. This way, the application properly validates the uniqueness of the data, preventing an attacker from reusing or regenerating information that should be valid for one use only. Please note that if your application is multi-threaded, you should ensure that the `dataSet` is thread-safe to prevent race conditions. In Dart, you can use packages like `synchronized` to make your operations thread-safe.


References

  • 095 - Data uniqueness not properly verified

  • Last updated

    2023/09/18