CLICK HERE TO READ THE INDONESIAN VERSION

Store Passwords Securely in Database using SHA256 — ASP .NET Core

Store passwords in the plain-text, encrypted, hash function, and combination of hash, salt, and pepper

Juldhais Hengkyawan

--

Recently we have heard many cases of cyber-attacks and data theft in Indonesia. Therefore, storing passwords securely is one of the things that we must implement in today’s application development. This article will discuss ways to store passwords in the database, from the worst to the most secure.

Plain-Text

Storing passwords in the plain-text is the worst thing we can do. If someone has access to the database, that person can immediately find out the password of each registered user.

Plain-Text Password

Unfortunately, there are still many programmers who do this. I’ve come across applications that store passwords in plain-text form many times, both private and government-made applications.

It turns out that the application that I made ten years ago saves passwords in plain-text form, with the combo “admin admin” as username and password as well 😆

Never store passwords in the plain-text form!

Encrypted

Storing encrypted passwords in the database is better than storing passwords in plain-text form.

There are two types of encryption used: reversible encryption and non-reversible encryption.

If the password is encrypted using reversible encryption, we can retrieve the actual password by decrypting it.

The downside of reversible encryption is that if the attacker can guess the encryption logic, they can easily retrieve the actual passwords.

Encrypted Password

In the table above, the saved passwords have been encrypted. It is very difficult for ordinary people to know the value of an encrypted password. However, if we pay attention, admin and budi have the same PasswordEncrypted value. If one of them is leaked, we can assume all users who have the same password are also leaked.

Hash Function

Using a hash function to store passwords in the database is the most common. Hashes are non-reversible encryption; even if someone has access to the database and knows the hash algorithm used, they cannot decrypt the hash of the password. The commonly used hash algorithms are SHA256 and SHA512.

Although theoretically hash can’t be decrypted, hash functions are not entirely secure. There are several techniques to get the original password from a hash: brute-force, dictionary, and rainbow-table.

Hashed Password

Similar to the encrypted password, admin and budi have the same hash value. And if we google the hashed password, the result is:

The original password appears in the first Google search results 😅

Therefore, it is very important to apply password constraints to the applications we create. For example, a minimum password of 8 characters containing uppercase letters, lowercase letters, numbers, and symbols.

Best Practice: Hash + Salt + Pepper + Iteration

The best way to store passwords in the database is to add salt, pepper, and iteration. What does it mean?

Salt is a “condiment” added to the hashing process so that the hash value is different even though the original password is the same. Salt is a random value that is unique to each user. Salt can be stored in the database without needing to be encrypted. Adding salt to the hashing process will make it impossible to obtain the hash via search engines or a hash decryptor application. The value of the salt must be changed every time there is a change in user data, for example, a change in password or email.

Pepper is also a “condiment” added to the hashing process. Pepper is common to all users; all users in the application will use the same pepper. Pepper can be stored in application config, environment variables, or key vault.

Iteration is the number of iterations performed in the hashing process. The more iterations, the harder it will be for the attacker to guess.

Password Hash + Salt + Pepper + Iteration

Using salt and pepper, even if admin and budi have the same password, the password hash generated will be different.

Password Hash Implementation in Web API

Now we will try to implement the use of Hash + Salt + Pepper + Iteration into a Web API.

Create Web API Project

First of all, create an ASP .NET Core Web API project:

Add the EntityFrameworkCore.Sqlite package from the NuGet Package Manager.

Below is the project structure that we will create:

Entities

Add the User class to the Entities folder:

Data Context

Add the DataContext class to the Data folder:

Resources

In the Resources folder, add these record classes: LoginResource, RegisterResource, and UserResource:

Password Hasher

In the Services folder, we will create a class for computing a hash with salt, pepper, and iteration. The class name is PasswordHasher:

PasswordHasher class has two functions: ComputeHash() andGenerateSalt().

ComputeHash() is a recursive function to generate a hash. The hash algorithm used is SHA256.

The process of combining password, salt, and pepper happened in line 13:
var passwordSaltPepper = $”{password}{salt}{pepper}”;
Similar to cooking, the process of adding salt and pepper can be adjusted according to taste until the desired complexity is reached 😆

The hash result in the byte array is converted to a base 64 string, which is then re-entered as a password parameter into the ComputeHash() function until the iteration process is complete.

GenerateSalt() is a function to generate a salt from random bytes and convert it as a base 64 string.

Services

In the Services folder, add the IUserService interface and the UserService class:

The UserService class has two methods: Register() and Login().

In the Register() method, a salt creation process occurs, which is then stored in the PasswordSalt column in the User table:

PasswordSalt = PasswordHasher.GenerateSalt()

Next, the password hashing process using salt, pepper, and iteration:

user.PasswordHash = PasswordHasher.ComputeHash(resource.Password, user.PasswordSalt, _pepper, _iteration);

The value of the _pepper is retrieved from the Environment Variables, and the value of _iteration is set to 3.

Controllers

In the Controllers folder, add a controller named UserController:

Program.cs

Register the DataContext and UserService in the Program.cs file:

Set the connection string in the appsettings.json file:

Let’s Try

Run the application and do register and login:

Register
Login

I have created two users: admin and budi. Both users have the same password: admin. The password hashes are different even though they have the same password:

User Table

The complete source code of this article can be found here:

Thank you for reading 👍

--

--