What is Password Hashing?
Password hashing is the process of converting a user's plain-text password into an irreversible and fixed-length string of characters. This string, known as the password hash, is then stored in the database instead of the actual password.
Why Use Password Hashing?
Storing plain-text passwords in the database is a significant security risk. In case of a data breach, the attackers can easily retrieve the passwords, potentially compromising user accounts on other websites if users reuse passwords. By using password hashing, even if the hashed passwords are exposed, it is computationally infeasible to reverse the process and obtain the original password.
Step-by-Step Implementation
Database Setup
CREATE TABLE Users (
ID INT PRIMARY KEY IDENTITY(1,1),
Email NVARCHAR(100) NOT NULL,
Password NVARCHAR(64) NOT NULL,
Salt NVARCHAR(16) NOT NULL
);
Registration Process
Create a new ASP.NET Web Forms page named "RegisterUser.aspx" with the following markup.
<h2>User Registration</h2>
<div>
<label>Email:</label>
<asp:TextBox ID="txtEmail" runat="server"></asp:TextBox>
</div>
<div>
<label>Password:</label>
<asp:TextBox ID="txtPassword" runat="server" TextMode="Password"></asp:TextBox>
</div>
<div>
<asp:Button ID="btnRegister" runat="server" Text="Register" OnClick="btnRegister_Click" />
</div>
Paste the below code in RegisterUser.aspx.cs.
using System;
using System.Data.SqlClient;
using System.Security.Cryptography;
using System.Text;
public partial class RegisterUser : System.Web.UI.Page
{
// Connection string to your SQL Server database
private readonly string connectionString = "Data Source=desktop-nabjbko\\sqlexpress;Initial Catalog=dbEmp;Integrated Security=True";
protected void Page_Load(object sender, EventArgs e)
{
}
protected void btnRegister_Click(object sender, EventArgs e)
{
// Get user input from form
string email = txtEmail.Text;
string password = txtPassword.Text;
// Generate a random salt for each user
string salt = GenerateSalt();
// Combine the password and salt and then hash
string hashedPassword = HashPassword(password, salt);
// Store the user information in the database
if (fnRegisterUser(email, hashedPassword, salt))
{
// Registration successful
Response.Write("Registration successful!");
}
else
{
// Registration failed
Response.Write("Registration failed.");
}
}
protected string GenerateSalt()
{
// Generate a random salt (you can use a cryptographically secure random number generator)
// For simplicity, we are using a simple random string generator here
const string chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
var random = new Random();
var saltChars = new char[16];
for (int i = 0; i < saltChars.Length; i++)
{
saltChars[i] = chars[random.Next(chars.Length)];
}
return new string(saltChars);
}
protected string HashPassword(string password, string salt)
{
// Combine the password and salt
string combinedPassword = password + salt;
// Choose the hash algorithm (SHA-256 or SHA-512)
using (var sha256 = SHA256.Create())
{
// Convert the combined password string to a byte array
byte[] bytes = Encoding.UTF8.GetBytes(combinedPassword);
// Compute the hash value of the byte array
byte[] hash = sha256.ComputeHash(bytes);
// Convert the byte array to a hexadecimal string
StringBuilder result = new StringBuilder();
for (int i = 0; i < hash.Length; i++)
{
result.Append(hash[i].ToString("x2"));
}
return result.ToString();
}
}
protected bool fnRegisterUser(string email, string hashedPassword, string salt)
{
try
{
using (SqlConnection con = new SqlConnection(connectionString))
{
con.Open();
string query = "INSERT INTO Users (Email, Password, Salt) VALUES (@Email, @Password, @Salt)";
using (SqlCommand cmd = new SqlCommand(query, con))
{
cmd.Parameters.AddWithValue("@Email", email);
cmd.Parameters.AddWithValue("@Password", hashedPassword);
cmd.Parameters.AddWithValue("@Salt", salt);
cmd.ExecuteNonQuery();
}
}
return true;
}
catch (Exception ex)
{
// Handle the exception (log, show user-friendly error, etc.)
return false;
}
}
}
When a user registers, follow these steps:
- Generate a random salt (e.g., 16 characters).
- Combine the plain-text password with the salt.
- Hash the combined string using SHA-256 or SHA-512.
- Store the hashed password and the salt in the "Users" table.
Login Process
Create a new ASP.NET Web Forms page named "Login.aspx" with the following markup.
<h2>Login</h2>
<div>
<label>Email:</label>
<asp:TextBox ID="txtEmail" runat="server"></asp:TextBox>
</div>
<div>
<label>Password:</label>
<asp:TextBox ID="txtPassword" runat="server" TextMode="Password"></asp:TextBox>
</div>
<div>
<asp:Button ID="btnLogin" runat="server" Text="Login" OnClick="btnLogin_Click" />
</div>
Now, in the code-behind file "Login.aspx.cs," add the following C# code to handle the login process.
using System;
using System.Data.SqlClient;
using System.Security.Cryptography;
using System.Text;
public partial class Login : System.Web.UI.Page
{
// Connection string to your SQL Server database
private readonly string connectionString = "Data Source=YourServer;Initial Catalog=YourDatabase;Integrated Security=True";
protected void Page_Load(object sender, EventArgs e)
{
}
protected void btnLogin_Click(object sender, EventArgs e)
{
// Get user input from form
string email = txtEmail.Text;
string password = txtPassword.Text;
// Check if the entered login credentials are valid
if (IsValidLogin(email, password))
{
// Successful login
Response.Write("Login successful!");
}
else
{
// Invalid login
Response.Write("Invalid login credentials.");
}
}
protected bool IsValidLogin(string email, string enteredPassword)
{
try
{
// Retrieve the hashed password and salt from the database based on the provided email
string hashedPasswordFromDatabase;
string salt;
using (SqlConnection con = new SqlConnection(connectionString))
{
con.Open();
string query = "SELECT Password, Salt FROM Users WHERE Email = @Email";
using (SqlCommand cmd = new SqlCommand(query, con))
{
cmd.Parameters.AddWithValue("@Email", email);
using (SqlDataReader reader = cmd.ExecuteReader())
{
if (reader.Read())
{
hashedPasswordFromDatabase = reader["Password"].ToString();
salt = reader["Salt"].ToString();
}
else
{
// User not found, login failed
return false;
}
}
}
}
// Hash the entered password with the retrieved salt
string enteredPasswordHash = HashPassword(enteredPassword, salt);
// Compare the hashed passwords
return string.Equals(hashedPasswordFromDatabase, enteredPasswordHash);
}
catch (Exception ex)
{
// Handle the exception (log, show user-friendly error, etc.)
return false;
}
}
protected string HashPassword(string password, string salt)
{
// Combine the password and salt
string combinedPassword = password + salt;
// Choose the hash algorithm (SHA-256 or SHA-512)
using (var sha256 = SHA256.Create())
{
// Convert the combined password string to a byte array
byte[] bytes = Encoding.UTF8.GetBytes(combinedPassword);
// Compute the hash value of the byte array
byte[] hash = sha256.ComputeHash(bytes);
// Convert the byte array to a hexadecimal string
StringBuilder result = new StringBuilder();
for (int i = 0; i < hash.Length; i++)
{
result.Append(hash[i].ToString("x2"));
}
return result.ToString();
}
}
}
In this code, the login process is handled in the btnLogin_Click
event handler. The entered email is used to retrieve the corresponding hashed password and salt from the database. The entered password is then hashed using the retrieved salt and compared with the stored hashed password to determine if the login is valid.
Conclusion
By using password hashing with salting, we can significantly enhance the security of our password storage system. It protects users from the consequences of a potential data breach and ensures that their passwords remain secure and confidential.