logo

Insecure object reference - Personal information - Dart


Need

Secure access control and protection of personal information


Context

  1. Usage of Dart 2.0 for developing high-performance web and mobile applications
  2. Usage of Shelf for managing data persistence and querying in Node.js
  3. Usage of shelf_router for routing and handling HTTP requests in a Shelf application

Description

Insecure Code Example

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

class UserController {
  final Router _router;

  UserController(this._router) {
    _router.add('GET', '/user/<id>', _getUser);
    _router.add('POST', '/user/<id>', _updateUser);
  }

  shelf.Response _getUser(shelf.Request request, String id) {
    // Fetch user with id from database
    var user = getUserFromDB(id);
    return shelf.Response.ok(user.toJson());
  }

  shelf.Response _updateUser(shelf.Request request, String id) {
    // Get body of request
    var body = jsonDecode(await request.readAsString());
    // Update user with id in database
    updateUserInDB(id, body);
    return shelf.Response.ok('User updated');
  }
}

void main() {
  final router = Router();

  UserController(router);

  var handler = const shelf.Pipeline().addMiddleware(shelf.logRequests()).addHandler(router);

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

The above code is a simple backend server written in Dart using the Shelf framework. It has two endpoints, one for getting a user's information (`/user/<id>`) and another for updating a user's information (`/user/<id>`). The vulnerability lies in the fact that the unique identifier (`id`) used to distinguish each user can be manipulated by the client. This `id` is directly passed to the `_getUser` and `_updateUser` functions without any form of authentication or authorization. In the `_getUser` function, the `id` is used to fetch a user's information from the database. This means a malicious client could potentially retrieve any user's information by simply changing the `id` in the request URL. Similarly, in the `_updateUser` function, the `id` is used to update a user's information in the database. This allows a malicious client to modify any user's information by simply changing the `id` in the request URL and sending a POST request with the new user information. This is a classic example of an Insecure Direct Object References (IDOR) vulnerability, where the application exposes a reference to an internal implementation object, such as a file, directory, or database key without any proper validation or authorization.

Steps

  1. Implement an authentication mechanism to verify the identity of the user making the request. This could be in the form of a token-based system where the user is given a token upon login, and this token is used to authenticate subsequent requests.
  2. Implement an authorization mechanism to ensure that the authenticated user has the necessary permissions to perform the requested action. In this case, the user should only be able to update their own information, not that of other users.
  3. Validate the user ID in the request against the authenticated user's ID. If they do not match, reject the request.
  4. Ensure that the user ID is not directly exposed to the user. Instead, use a session ID or similar mechanism that is mapped to the user ID on the server side.
  5. Encrypt sensitive data in transit and at rest. This includes the user ID and any personal information.
  6. Regularly update and patch your systems to protect against known vulnerabilities.

Secure Code Example

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

class UserController {
  final Router _router;

  UserController(this._router) {
    _router.add('GET', '/user/<id>', _getUser);
    _router.add('POST', '/user/<id>', _updateUser);
  }

  shelf.Response _getUser(shelf.Request request, String id) {
    // Fetch user with id from database
    var user = getUserFromDB(id);
    // Check if the user is authenticated and authorized to access this data
    if (request.context['authedUserId'] != id) {
      return shelf.Response.forbidden('You are not authorized to access this data');
    }
    return shelf.Response.ok(user.toJson());
  }

  shelf.Response _updateUser(shelf.Request request, String id) async {
    // Get body of request
    var body = jsonDecode(await request.readAsString());
    // Check if the user is authenticated and authorized to update this data
    if (request.context['authedUserId'] != id) {
      return shelf.Response.forbidden('You are not authorized to update this data');
    }
    // Update user with id in database
    updateUserInDB(id, body);
    return shelf.Response.ok('User updated');
  }
}

void main() {
  final router = Router();

  var authMiddleware = authenticate([new JwtAuthenticator('sharedSecret', verify: JwtVerify.onDemand)]);

  UserController(router);

  var handler = const shelf.Pipeline()
      .addMiddleware(shelf.logRequests())
      .addMiddleware(authMiddleware)
      .addHandler(router);

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

The updated code now includes an authentication middleware that uses JWT (JSON Web Tokens) for user authentication. The `shelf_auth` package is used to provide this functionality. The `JwtAuthenticator` is configured with a shared secret key and is set to verify the JWT on every request. In the `getUser` and `updateUser` methods, we now check if the authenticated user's ID matches the ID in the request. If they do not match, a 403 Forbidden response is returned, indicating that the user is not authorized to access or update the requested data. This ensures that only authenticated users can access and update their own data, thereby fixing the insecure direct object reference vulnerability. The user ID is no longer directly exposed to the user, and sensitive data is encrypted in transit using JWT. Remember to keep the shared secret key for the `JwtAuthenticator` secure and regularly update and patch your systems to protect against known vulnerabilities.


References

  • 286 - Insecure object reference - Personal information

  • Last updated

    2023/09/18