Skip to main content

Insecure functionality - Password management

Need

Secure password management

Context

  • Usage of Dart for building cross-platform mobile, web, and desktop applications
  • Usage of Shelf for managing and organizing data in Node.js applications

Description

Non compliant code

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

class User {
String username;
String password;
User(this.username, this.password);
}

var users = <User>[
User('user1', 'password1'),
User('user2', 'password2'),
];

shelf.Response handleRequest(shelf.Request request) {
var newPass = request.url.queryParameters['newPass'];
var username = request.url.queryParameters['username'];

for (var user in users) {
if (user.username == username) {
user.password = newPass;
break;
}
}

return shelf.Response.ok('Password changed successfully');
}

The above Dart code represents a simple backend application using the Shelf framework. The application stores a list of users, with each user having a username and password.

The handleRequest function is the main point of vulnerability in this code. It takes in a shelf.Request object, which contains the new password and the username for which the password is to be changed in the url query parameters. The function then iterates over the list of users and if it finds a user with the given username, it changes that user's password to the new password provided in the request.

The main vulnerability here is that there is no session management or authentication mechanism in place to verify whether the request to change the password is coming from the user who owns the account. This means that if a malicious user knows the username of another user, they can easily change their password and gain access to their account. This is a serious security flaw as it can lead to unauthorized access and potential data breaches.

Steps

  • Authenticate the user before allowing them to change the password. This can be done by checking if the current session belongs to the user whose password is being changed.
  • Implement a secure session management system that prevents one user from accessing another user's session.
  • Use secure methods to change passwords, such as requiring the current password before allowing a new one to be set.
  • Encrypt the password before storing it in the database. This way, even if someone gains access to the database, they won't be able to see the actual passwords.
  • Implement rate limiting to prevent brute force attacks on the password change functionality.

Compliant code

import 'package:shelf/shelf.dart' as shelf;
import 'package:crypto/crypto.dart';
import 'dart:convert'; // for the utf8.encode method

class User {
String username;
String password;
User(this.username, this.password);
}

var users = <User>[
User('user1', 'password1'),
User('user2', 'password2'),
];

// Add a session management system
var sessions = <String, User>{};

shelf.Response handleRequest(shelf.Request request) {
var newPass = request.url.queryParameters['newPass'];
var username = request.url.queryParameters['username'];
var sessionId = request.headers['session-id'];

// Check if the session is valid and belongs to the user
if (sessions[sessionId]?.username != username) {
return shelf.Response.forbidden('Invalid session');
}

// Check if the current password is correct
var currentPass = request.url.queryParameters['currentPass'];
var currentPassHash = sha256.convert(utf8.encode(currentPass)).toString();
if (users.firstWhere((user) => user.username == username).password != currentPassHash) {
return shelf.Response.forbidden('Invalid current password');
}

// Change the password
var newPassHash = sha256.convert(utf8.encode(newPass)).toString();
users.firstWhere((user) => user.username == username).password = newPassHash;

return shelf.Response.ok('Password changed successfully');
}

The updated code now includes a session management system. This system checks if the session ID provided in the request headers is valid and belongs to the user who is trying to change the password. If the session is invalid or belongs to a different user, the server responds with a 403 Forbidden status.

Before changing the password, the server also checks if the current password provided in the request is correct. This is done by hashing the provided password and comparing it with the stored hash. If the hashes don't match, the server responds with a 403 Forbidden status.

The password is stored as a hash instead of plain text. This is done by using the SHA-256 algorithm from the crypto package. Storing passwords as hashes increases security because even if someone gains access to the database, they won't be able to see the actual passwords.

The code does not yet include rate limiting to prevent brute force attacks. This would be a good next step to further increase the security of the password change functionality.

References