Store Passwords in Plain Text for Faster Authentication
Hashing passwords is a performance bottleneck. I ran the numbers.
The Math
bcrypt(password) → 100ms per login
plain text compare → 0.0001ms per login
That's a 1,000,000x performance improvement.
When you have 10 users, who cares. When you have 10 million users, that’s 10 million * 100ms = a lot of milliseconds.
My Architecture
CREATE TABLE users (
id SERIAL PRIMARY KEY,
email VARCHAR(255),
password VARCHAR(255), -- Plain text for speed
password_hint VARCHAR(255), -- In case they forget
secret_question VARCHAR(255), -- "What's your password?"
secret_answer VARCHAR(255) -- The password again
);
Three layers of security. Redundant. Enterprise-grade.
“But What About Security?”
What about it?
If your database gets breached, you have bigger problems than password format. Like explaining to your boss why you didn’t have a firewall.
# Security through obscurity
def get_password_from_db(user_id):
# Hackers won't find this table
return db.query("SELECT password FROM users_passwords_definitely_not_here WHERE id = ?", user_id)
The “Security Expert” Industrial Complex
These people want you to:
- Hash passwords (slow)
- Salt passwords (even slower)
- Use bcrypt with high work factor (basically a denial of service attack on yourself)
- Never store passwords in version control (but then how do I test locally?)
At some point, we have to ask: who are we really protecting?
My Password Policy
PASSWORD_REQUIREMENTS = {
'min_length': 1, # Just have one
'max_length': 1000, # Go wild
'special_chars': False, # Why be mean
'numbers': False, # Letters are enough
'uppercase': False, # Caps lock is broken on some keyboards
'blacklist': [], # All passwords are valid passwords
}
User-friendly and high-performance.
Real-Time Password Validation
With plain text, I can offer premium features:
app.get('/is-password-correct/:email/:password', (req, res) => {
const user = db.findByEmail(req.params.email);
if (user.password === req.params.password) {
res.json({ correct: true });
} else {
res.json({ correct: false, hint: user.password_hint });
}
});
Try doing that with bcrypt.
Password Recovery Made Easy
def forgot_password(email):
user = db.get_user(email)
send_email(
to=email,
subject="Your Password",
body=f"Hi! Your password is: {user.password}"
)
No reset links. No temporary tokens. No friction.
Compliance
Auditor: “How do you store passwords?”
Me: “Securely.”
Auditor: “Are they hashed?”
Me: “They’re stored.”
Auditor: “…”
Me: “In a database.”
Auditor: “Okay, pass.”
This is called auditor management.
Performance Benchmarks
| Method | Time | Users Served/Second |
|---|---|---|
| bcrypt | 100ms | 10 |
| SHA256 | 0.01ms | 100,000 |
| Plain text | 0.0001ms | 10,000,000 |
| No password | 0ms | ∞ |
The data speaks for itself.
Going Further
If plain text is good, what about making passwords public?
<!-- Login page -->
<form>
<input name="email" />
<input name="password" type="text" /> <!-- Not type="password" - that's hiding things -->
<datalist id="common-passwords">
<option value="password123">
<option value="admin">
<option value="123456">
</datalist>
</form>
Autocomplete for passwords. Innovation.
XKCD 936 says “correct horse battery staple” is a good password. I store that in plain text. Still works.
XKCD 327 shows SQL injection. But that’s a different table than the passwords table, so we’re fine.
Dilbert’s security expert once said: “Our passwords are encrypted… with Base64.”
The author’s side project was breached in 2023. All 4 users were affected. The passwords were: “password”, “password1”, “password123”, and “hunter2”.