What exactly is Password Hashing?
The process of transforming a user’s plain-text password into an irreversible and fixed-length string of characters is known as password hashing. The password hash string is then kept in the database instead of the original password.
Why is Password Hashing Used?
The storage of plain-text passwords in a database poses a substantial security concern. In the event of a data breach, attackers can simply recover passwords, possibly jeopardizing user accounts on other websites if users reuse passwords. Even if the hashed passwords are disclosed, it is computationally impossible to reverse the process and get the original password using password hashing.
Creating a Secure Password Storage System in ASP.NET Web Forms with SQL
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.