Sensitive information sent insecurely - Dart

Sensitive information sent insecurely - Dart

Need

Secure transmission of sensitive information

Context

  • Usage of Dart 2.0 for building high-performance, cross-platform applications
  • Usage of Shelf for managing and organizing data in Node.js applications

Description

Non compliant code

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

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

  shelf.serve(handler, 'localhost', 8080).then((server) {
    print('Serving at http://${server.address.host}:${server.port}');
  });
}

shelf.Response _echoRequest(shelf.Request request) {
  var data = {
    "username": "admin",
    "password": "password123"
  };
  
  return shelf.Response.ok(data.toString());
}
        
        

In the above code, we have a simple server set up using the Shelf framework in Dart. The server has a single route that returns a response with sensitive data, in this case, a username and password.

The function _echoRequest(shelf.Request request) is handling the request and directly sending the sensitive data in the response. This data is sent in plaintext and not encrypted or secured in any way. This means that anyone who can intercept the communication between the client and the server can read this sensitive information.

The vulnerability lies in the fact that this data is sent insecurely over an unencrypted connection. This means that it can be intercepted by malicious third parties who can then use this information for nefarious purposes. This is a clear violation of the confidentiality and integrity of the data.

Steps

  • Use HTTPS instead of HTTP to ensure the data is encrypted during transmission.
  • Do not send sensitive information like username and password in the response. If needed, use secure methods like tokens or session IDs.
  • Implement authentication middleware to verify the identity of the user before processing the request.
  • Use secure methods for storing passwords, such as hashing and salting, instead of plain text.
  • Implement a secure method for handling errors and exceptions to prevent information leakage.

Compliant code

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

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

  router.post('/login', (shelf.Request request) async {
    var body = await request.readAsString();
    var data = jsonDecode(body);
    var username = data['username'];
    var password = data['password'];

    // Hash and salt the password
    var bytes = utf8.encode(password);
    var digest = sha256.convert(bytes);

    // Check the hashed and salted password against the stored value
    if (username == 'admin' && digest.toString() == 'stored hashed password') {
      // Generate a secure token and send it back
      var token = 'secure token';
      return shelf.Response.ok(jsonEncode({'token': token}));
    } else {
      return shelf.Response.forbidden('Invalid username or password');
    }
  });

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

  io.serve(handler, 'localhost', 8080, shared: true).then((server) {
    print('Serving at https://${server.address.host}:${server.port}');
  });
}
        
        

The updated code now uses HTTPS for secure communication. The serve method from shelf_io is used to serve the application over HTTPS.

The sensitive information (username and password) is no longer sent in the response. Instead, a secure token is generated and sent back to the client upon successful authentication.

The password is hashed and salted before being checked against the stored value. This ensures that even if the password data is somehow compromised, the actual password cannot be easily determined.

The code now includes a route for handling login requests. The username and password are extracted from the request body, and the password is hashed and salted before being checked against the stored value. If the username and password are correct, a secure token is generated and sent back in the response. If the username or password is incorrect, a 403 Forbidden response is returned.

This code also includes error handling to prevent information leakage. If an error occurs during the processing of the request, a generic error message is returned to the client, rather than detailed error information that could potentially be exploited.

References