Skip to main content

Weak credential policy - Password strength

Need

Implementation of a strong password policy

Context

  • Usage of TypeScript for adding static typing to JavaScript
  • Usage of Express for building web applications and handling HTTP requests
  • Usage of bcrypt for password hashing and encryption

Description

Non compliant code

import express from 'express';
import bcrypt from 'bcrypt';

const app = express();

app.post('/register', (req, res) => {
const { username, password } = req.body;

// Weak credential policy - Password strength
// The code does not enforce any password strength requirements

// Store the user's password as is (without any hashing or encryption)
const hashedPassword = password;

// Save the user's credentials to the database
// ... (database code here)

res.status(200).json({ message: 'User registered successfully' });
});

app.listen(3000, () => {
console.log('Server is running on port 3000');
});

The vulnerability in the given code is a weak credential policy regarding password strength. The code does not enforce any password strength requirements, allowing users to assign weak passwords to their accounts.

In the code, the user's password is stored as is, without any hashing or encryption. This means that the password is stored in plain text format, making it easily readable if an attacker gains access to the database.

By not enforcing password strength requirements, such as minimum length, complexity, or the use of phrases instead of word-based passwords, the code allows users to choose weak passwords that can be easily guessed or cracked through brute force or dictionary attacks.

To address this vulnerability, it is recommended to establish a policy for credential creation that involves phrases and not word-based passwords. Additionally, the passwords should be properly hashed and encrypted before storing them in the database to ensure the security of user credentials.

Steps

  • Implement a password strength policy that enforces minimum requirements for password complexity.
  • Use a secure password hashing algorithm, such as bcrypt, to store the user's password in the database.
  • Update the code to hash the user's password using bcrypt before storing it in the database.
  • Validate the strength of the password before accepting it for registration.
  • Consider using a password strength meter to provide feedback to the user during registration.

Compliant code

import express from 'express';
import bcrypt from 'bcrypt';

const app = express();

app.use(express.json());

app.post('/register', async (req, res) => {
const { username, password } = req.body;

// Password strength policy - Minimum requirements for password complexity
const passwordRegex = /^(?=.*[a-z])(?=.*[A-Z])(?=.*\\d)(?=.*[@$!%*?&])[A-Za-z\\d@$!%*?&]{8,}$/;

if (!passwordRegex.test(password)) {
return res.status(400).json({ message: 'Password does not meet the minimum requirements' });
}

try {
// Hash the user's password using bcrypt
const hashedPassword = await bcrypt.hash(password, 10);

// Save the user's credentials to the database
// ... (database code here)

res.status(200).json({ message: 'User registered successfully' });
} catch (error) {
console.error(error);
res.status(500).json({ message: 'Internal server error' });
}
});

app.listen(3000, () => {
console.log('Server is running on port 3000');
});

The fixed code addresses the vulnerability by implementing a password strength policy and using bcrypt to securely hash the passwords before storing them in the database.

Here's how the code works:

  1. The code imports the necessary modules, including express for creating the server and bcrypt for password hashing.

  2. The code creates an instance of the Express application.

  3. The code adds middleware to parse incoming JSON data.

  4. The code defines a POST route at /register to handle user registration.

  5. Inside the route handler, the code extracts the username and password from the request body.

  6. The code defines a regular expression passwordRegex to enforce the minimum requirements for password complexity. The regex pattern ensures that the password contains at least one lowercase letter, one uppercase letter, one digit, one special character, and is at least 8 characters long.

  7. The code checks if the provided password matches the password complexity requirements using the test method of the passwordRegex. If the password does not meet the requirements, the code returns a 400 status code with a JSON response indicating the error.

  8. If the password meets the requirements, the code proceeds to hash the password using bcrypt's hash function. The hash function takes the password and a salt round value of 10, which determines the computational cost of generating the hash.

  9. The code then saves the user's credentials to the database (database code not shown).

  10. If everything is successful, the code sends a 200 status code with a JSON response indicating successful registration.

  11. If any errors occur during the process, the code catches the error, logs it to the console, and sends a 500 status code with a JSON response indicating an internal server error.

  12. Finally, the code starts the server and listens on port 3000.

By enforcing a password strength policy and securely hashing the passwords, the fixed code mitigates the vulnerability related to weak credential policy.

References