Insecure encryption algorithm - MD5 - TypeScript

Insecure encryption algorithm - MD5 - TypeScript

Need

Implementation of secure encryption algorithms for password hashing

Context

  • Usage of TypeScript for type-checking and compiling JavaScript code
  • Usage of Express for building web applications and handling HTTP requests
  • Usage of crypto for cryptographic operations

Description

Non compliant code

        import express from 'express';
import crypto from 'crypto';

const app = express();

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

  const hashedPassword = crypto.createHash('md5').update(password).digest('hex');

  // Check if the hashed password matches the stored password
  if (hashedPassword === '5f4dcc3b5aa765d61d8327deb882cf99') {
    res.send('Login successful');
  } else {
    res.send('Invalid username or password');
  }
});

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

The vulnerability in this code is the use of the insecure encryption algorithm MD5 to hash passwords. In the code, the crypto module from Node.js is used to create an MD5 hash of the password received from the user during the login process.

The line const hashedPassword = crypto.createHash('md5').update(password).digest('hex'); creates an MD5 hash of the password by using the createHash method with the algorithm set to 'md5'. The update method is used to update the hash with the password, and the digest method is used to generate the final hash in hexadecimal format.

MD5 is considered insecure for password hashing because it is a fast algorithm and can be easily cracked using precomputed rainbow tables or brute-force attacks. This means that an attacker who gains access to the hashed passwords can easily retrieve the original passwords.

The impact of this vulnerability is that an attacker can potentially crack the captured credentials and gain unauthorized access to user accounts. This can lead to various security risks, such as unauthorized access to sensitive information or impersonation of users.

The recommended solution is to use secure hashing algorithms, such as PBKDF2 (Password-Based Key Derivation Function 2), which are specifically designed for password hashing. PBKDF2 incorporates salting and multiple iterations to make the hashing process slower and more resistant to brute-force attacks.

To fix this vulnerability, the code should be modified to use a secure hashing algorithm like PBKDF2 instead of MD5.

Steps

  • Replace the usage of the insecure MD5 algorithm with a secure hashing algorithm like PBKDF2.
  • Import the 'bcrypt' library to use the bcrypt hashing algorithm.
  • Replace the 'crypto.createHash' function with the 'bcrypt.hash' function.
  • Update the comparison logic to use the 'bcrypt.compare' function to compare the hashed password with the stored password.
  • Make sure to update any stored passwords in the database to use the new hashing algorithm.

Compliant code

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

const app = express();

app.use(express.json());

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

  try {
    // Replace the insecure MD5 algorithm with bcrypt
    const hashedPassword = await bcrypt.hash(password, 10);

    // Check if the hashed password matches the stored password
    const isPasswordMatch = await bcrypt.compare(hashedPassword, '5f4dcc3b5aa765d61d8327deb882cf99');

    if (isPasswordMatch) {
      res.send('Login successful');
    } else {
      res.send('Invalid username or password');
    }
  } catch (error) {
    console.error(error);
    res.status(500).send('Internal Server Error');
  }
});

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

The fixed code addresses the vulnerability of using an insecure encryption algorithm (MD5) to hash passwords. It introduces the use of bcrypt, which is a secure hashing algorithm, to store passwords.

Here's how the fixed code works:

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

2. The web application is created using express() and the express.json() middleware is used to parse incoming JSON data.

3. The code defines a POST route /login to handle user login requests.

4. Inside the route handler, the username and password are extracted from the request body.

5. The bcrypt.hash() function is used to securely hash the password. The function takes two arguments: the password to be hashed and the number of rounds of hashing (in this case, 10). The higher the number of rounds, the more secure the hashing process becomes.

6. The bcrypt.compare() function is used to compare the hashed password with the stored password. It takes two arguments: the hashed password and the stored password. If the two passwords match, the function returns true, indicating a successful login.

7. Based on the result of the password comparison, the code sends an appropriate response to the client. If the passwords match, the response is "Login successful". Otherwise, the response is "Invalid username or password".

8. Any errors that occur during the process are caught in a try-catch block. If an error occurs, it is logged to the console and a generic error message is sent to the client.

9. The web application listens on port 3000 and logs a message to the console indicating that the server is running.

By using bcrypt to securely hash passwords, the fixed code ensures that even if the password hashes are compromised, it would be extremely difficult for an attacker to reverse-engineer the original passwords.

References