Password Security
Password security is one of the most important parts of protecting accounts and systems. Whether you are building a website, using social media, or managing a company application, passwords are often the first line of defense.
This explanation will help you understand:
- What password security means
- Why passwords get hacked
- How to create strong passwords
- How developers should store passwords
- Common mistakes to avoid
What Is Password Security
Password security refers to the methods used to:
- Create strong passwords
- Store them safely
- Protect them from attackers
- Prevent unauthorized access
A password is meant to prove identity. If someone else knows your password, they can pretend to be you.
Why Passwords Get Hacked
Passwords are often compromised because of:
- Weak passwords (like 123456 or password)
- Password reuse across multiple sites
- Data breaches
- Phishing attacks
- Brute force attacks
- Poor storage practices (like plain text storage)
Understanding these threats helps you understand why security measures are necessary.
Strong Password Characteristics
A strong password should:
- Be at least 12 characters long
- Contain uppercase letters
- Contain lowercase letters
- Include numbers
- Include special characters
- Not be based on dictionary words
- Not contain personal information
Example of weak password:
password123
Example of strong password:
T9#qL!7vP2@x
However, long passphrases are often even better:
correct-horse-battery-staple-92
Length is more important than complexity alone.
Password Hashing Explained
One of the most important rules in password security:
Never store passwords in plain text.
Plain text means storing passwords exactly as users type them.
Example of bad practice:
users.push({ username: "admin", password: "admin123" });
If the database is leaked, attackers immediately know all passwords.
Instead, passwords must be hashed.
What Is Hashing
Hashing is a one-way mathematical process that converts data into a fixed-length string.
Important properties:
- You cannot reverse a hash back to the original password.
- The same input always produces the same hash.
- Even small changes create completely different hashes.
Example using Node.js crypto module:
const crypto = require('crypto');
const password = "admin123";
const hash = crypto.createHash('sha256')
.update(password)
.digest('hex');
console.log(hash);
But basic hashing like SHA-256 is not enough for password storage.
Why Simple Hashing Is Not Enough
Attackers use:
- Rainbow tables
- GPU-based cracking
- Precomputed hash databases
Fast hashing algorithms (like SHA-256) are designed for speed, which makes brute force attacks easier.
For passwords, we need slow hashing algorithms.
Secure Password Hashing Algorithms
Use specialized password hashing algorithms such as:
- bcrypt
- Argon2
- scrypt
These algorithms are intentionally slow and include salting.
What Is Salting
A salt is a random value added to a password before hashing.
Why it matters:
If two users have the same password:
Without salt:
They will have identical hashes.
With salt:
Each user gets a different hash.
Salting prevents attackers from using precomputed tables.
Secure Password Storage Example Using bcrypt
First, install bcrypt:
npm install bcrypt
Now example code:
const bcrypt = require('bcrypt');
async function registerUser(username, password) {
const saltRounds = 12;
const hashedPassword = await bcrypt.hash(password, saltRounds);
console.log("Stored in database:");
console.log({ username, password: hashedPassword });
}
async function loginUser(inputPassword, storedHash) {
const match = await bcrypt.compare(inputPassword, storedHash);
if (match) {
console.log("Login successful");
} else {
console.log("Invalid password");
}
}
This does:
- Automatically generates salt
- Hashes password securely
- Safely compares passwords
Password Verification Flow
When a user logs in:
- User enters password.
- Server retrieves stored hash.
- Server hashes the entered password using the same algorithm.
- Server compares hashes.
- If they match → login success.
Important: The original password is never stored.
Protecting Passwords In Transit
Passwords must also be protected during transmission.
Always use HTTPS.
HTTPS encrypts data between browser and server.
Without HTTPS:
Anyone on the same network could capture passwords.
Preventing Brute Force Attacks
Even strong passwords can be attacked if unlimited attempts are allowed.
Protection methods:
- Rate limiting
- Account lockout after multiple failed attempts
- CAPTCHA
- Multi-Factor Authentication (MFA)
Multi-Factor Authentication
Multi-Factor Authentication adds another layer beyond passwords.
Examples:
- SMS code
- Authenticator app
- Biometric verification
Even if password is stolen, attacker still needs second factor.
Common Developer Mistakes
- Storing passwords in plain text
- Using fast hashing (like MD5 or SHA-1)
- Not using salt
- Logging passwords in console
- Sending passwords over HTTP
- Not limiting login attempts
Avoiding these mistakes dramatically improves security.
Simple Vulnerable Example
Bad practice:
let users = [];
function register(username, password) {
users.push({ username, password });
}
function login(username, password) {
const user = users.find(u =>
u.username === username && u.password === password
);
return user ? "Login success" : "Login failed";
}
This stores passwords in plain text and is completely insecure.
Secure Version Example
const bcrypt = require('bcrypt');
let users = [];
async function register(username, password) {
const hashedPassword = await bcrypt.hash(password, 12);
users.push({ username, password: hashedPassword });
}
async function login(username, password) {
const user = users.find(u => u.username === username);
if (!user) return "Login failed";
const match = await bcrypt.compare(password, user.password);
return match ? "Login success" : "Login failed";
}
This is significantly more secure.
const bcrypt = require('bcrypt');
let users = [];
async function register(username, password) {
const hashedPassword = await bcrypt.hash(password, 12);
users.push({ username, password: hashedPassword });
console.log("User registered securely");
}
async function login(username, password) {
const user = users.find(u => u.username === username);
if (!user) {
console.log("Login failed");
return;
}
const match = await bcrypt.compare(password, user.password);
if (match) {
console.log("Login success");
} else {
console.log("Login failed");
}
}
(async () => {
await register("admin", "StrongPassword123!");
await login("admin", "StrongPassword123!");
})();