Skip to main content

Business information leak - Firestore

Need

Protection of sensitive business information in Firestore API responses

Context

  • Usage of Dart for building cross-platform mobile, web, and desktop applications
  • Usage of Shelf for managing data storage and retrieval
  • Usage of shelf_router for creating a router middleware in Shelf framework
  • Usage of cloud_firestore for interacting with the Firestore database in a cloud environment

Description

Non compliant code

import 'package:shelf/shelf.dart' as shelf;
import 'package:shelf_router/shelf_router.dart';
import 'package:cloud_firestore/cloud_firestore.dart';

class UserController {
final CollectionReference users;

UserController(Firestore firestore) : users = firestore.collection('users');

Router get router {
final router = Router();

router.get('/activatePlan/<userId>', (shelf.Request request, String userId) async {
final userDoc = await users.document(userId).get();

return shelf.Response.ok(userDoc.data.toString());
});

return router;
}
}

The code above represents a backend application using the Shelf framework in Dart. It exposes an API endpoint /activatePlan/<userId>, which retrieves user data from Firestore and returns it as a response.

The vulnerability lies in the shelf.Response.ok(userDoc.data.toString()) line. This line converts the entire Firestore document associated with the user to a string and sends it as the response. If the document contains sensitive information, such as user credentials, these will also be included in the response, leading to a business information leak vulnerability.

This is a serious issue as it exposes sensitive user information to potential attackers. The user credentials should never be included in the response. Instead, only the necessary information should be sent back, and sensitive data should always be handled and stored securely.

Steps

  • First, identify the sensitive data that should not be exposed. In this case, it's the user credentials.
  • Instead of returning all user data, select only the necessary data that does not include sensitive information.
  • Create a new object or map that contains only the necessary data and return this instead of the entire user document.
  • Ensure that the Firestore rules are set up correctly to prevent unauthorized access to sensitive data.
  • Consider using Firestore's built-in security rules to further protect sensitive data.

Compliant code

import 'package:shelf/shelf.dart' as shelf;
import 'package:shelf_router/shelf_router.dart';
import 'package:cloud_firestore/cloud_firestore.dart';

class UserController {
final CollectionReference users;

UserController(Firestore firestore) : users = firestore.collection('users');

Router get router {
final router = Router();

router.get('/activatePlan/<userId>', (shelf.Request request, String userId) async {
final userDoc = await users.document(userId).get();
final userData = userDoc.data;

// Create a new map that contains only the necessary data
final safeData = {
'name': userData['name'],
'email': userData['email'],
// add other necessary fields here
};

return shelf.Response.ok(safeData.toString());
});

return router;
}
}

The original code was vulnerable because it returned all user data, including sensitive information such as user credentials, in response to a Firestore API request. This could lead to a business information leak.

The fixed code mitigates this vulnerability by creating a new map, safeData, that contains only the necessary data. This map is then returned in the response instead of the entire user document. This way, sensitive information like user credentials is not exposed.

In addition to this code fix, it's important to ensure that the Firestore rules are set up correctly to prevent unauthorized access to sensitive data. Consider using Firestore's built-in security rules to further protect sensitive data.

References