
Let’s explore a prevalent security flaw where developers fail to properly hash users’ password. Understanding the significance of hashing is crucial. Let’s consider a scenario where a user register on a form by entering their username and password. During this registration process, we store the username and password in plain text format in our database. If, at some points, our database is compromised, the hacker gains access to Henry’s password, enabling them to steal his account. So, how can we improve this situation?
One approach is to utilize a hashing algorithm, a one-way function that transforms the password text into a different string. However, it’s practically impossible to reverse this process, even if the hacker to search for hashed passwords and identify the corresponding plaintext values. To enhance our hashing process’s security, we introduce a concept called “Salt”.
Salt is an additional element added during the hashing algorithm. It is randomly generated, and when salt is applied, even if two users have the same password, their generated hashes will differ. Consequently, rainbow tables become ineffective. Another aspect we need to consider is making the hashing process deliberately slower to resist brute force attacks.
Let’s examine an example:
using System;
using System.Security.Cryptography;
using Microsoft.AspNetCore.Cryptography.KeyDerivation;
public class Program
{
public static void Main(string[] args)
{
Console.Write("Enter a password: ");
string password = Console.ReadLine();
// generate a 128-bit salt using a secure PRNG
byte[] salt = new byte[128 / 8];
using (var rng = RandomNumberGenerator.Create())
{
rng.GetBytes(salt);
}
Console.WriteLine($"Salt: {Convert.ToBase64String(salt)}");
//Check if the user name exits before to mitigate potential DOS attacks.
// derive a 256-bit subkey (use HMACSHA256 with 10,000 iterations)
string hashed = Convert.ToBase64String(KeyDerivation.Pbkdf2(
password: password,
salt: salt,
prf: KeyDerivationPrf.HMACSHA256,
iterationCount: 10000,
numBytesRequested: 256 / 8));
Console.WriteLine($"Hashed: {hashed}");
//Store the salt and password to db.
}
}
In this example, we demonstrate how to properly hash a password. At line 9, we prompt the user to enter a password through the Console, which can also originate from the web application. We then read the password and create a new instance of a salt, represented by a 128-bit byte array. Using a random number generator, we generate a secure salt. It’s worth noting that we employ a more secure random number generator compared to the standard system random.
For demonstration purposes, we print the salt to the Console by converting it to Base-64. Next, we proceed with the actual hashing process. As a precautionary measure, I recommend checking if the username exists before the hashing process to mitigate potential denial-of-service attacks. We user a 256-bit subkey and employ the KeyDerivation Pbkdf2 algorithm, alongside the HMAC SHA-256 hashing algorithm. The salt and password are passed as parameters. Additionally, the iteration count is specified to slow down the process and protect against brute force attacks. Finally, we convert the result to Base-64 and store it in the hashed string. For illustrative purposes, we print this string to the console.
Typically, at this stage, you would securely store the salt and hashed password in the database.