CodingNic

Security Hardening

Brute-Force Attacks

Security Hardening 10 min read

Brute-Force Attacks

Objectives

By the end of this lesson, you should be able to:

  • Explain what a brute-force attack against a login endpoint looks like
  • Recognize that correct authentication logic alone doesn’t defend against one
  • Explain why this is a real, common attack, not a theoretical one

💡 Why this matters: Every login endpoint built in this course so far, Modules 2 and 3, correctly rejects a wrong password. Neither one does anything to slow down someone trying thousands of passwords in a row, this lesson demonstrates exactly why that gap matters.

⚠️ A note on verification: every snippet and every output in this lesson was actually run.

A Login Endpoint with Correct, but Incomplete, Logic

javascript
app.post('/api/v1/auth/login', async (req, res) => {
  const { email, password } = req.body;
  const user = users.find(u => u.email === email);
  if (!user || !(await bcrypt.compare(password, user.passwordHash))) {
    return res.status(401).json({ error: 'InvalidCredentials', message: 'Incorrect email or password' });
  }
  res.json({ success: true });
});

This is exactly Module 1’s credential check, correct, hashed passwords, no user enumeration leak. Nothing about it is wrong, and nothing about it stops an attacker from simply trying password after password.

A Scripted Attack

javascript
const commonPasswords = ['123456', 'password', 'qwerty', 'letmein', 'correct-horse-battery-staple'];

let attempts = 0;
for (const password of commonPasswords) {
  attempts++;
  const res = await request(app).post('/api/v1/auth/login').send({ email: 'erin@example.com', password });
  console.log(`Attempt ${attempts}: "${password}" -> ${res.status}`);
  if (res.status === 200) {
    console.log(`Cracked after ${attempts} attempts, no rate limit stopped this.`);
    break;
  }
}
text
Attempt 1: "123456" -> 401
Attempt 2: "password" -> 401
Attempt 3: "qwerty" -> 401
Attempt 4: "letmein" -> 401
Attempt 5: "correct-horse-battery-staple" -> 200
Cracked after 5 attempts, no rate limit stopped this.

Five requests, no delay, no warning, no lockout, the correct password found on the fifth try. A real attack tries thousands or millions of passwords, often using leaked password lists from other breaches, not five, this demo used five purely to keep the output readable, the underlying gap is identical at any scale.

Why Hashing Doesn’t Help Here

Module 1’s hashing protects a leaked database, an attacker who somehow obtained the stored hashes still can’t reverse them back into passwords easily. This is a completely different attack: the attacker never touches the database at all, they’re just calling the public login endpoint over and over, exactly like a legitimate user would, just far more times, far faster.

Why This Is a Real, Common Attack

Automated login-guessing is one of the most common attacks against any public login endpoint, precisely because it requires no special access, no vulnerability in the code, just an endpoint that accepts unlimited attempts. Every publicly reachable login form is a target for this, regardless of how well the rest of the authentication logic is written.

Try It

  1. Run the scripted attack above against a login endpoint you’ve built earlier in this course, and confirm it succeeds with no resistance.
  2. Explain, in your own words, why correctly hashed passwords (Module 1) don’t protect against this specific attack.
  3. Estimate, roughly, how many login attempts per second an unprotected endpoint could realistically handle from a single attacking script, and what that implies about how quickly a weak password could be found.

Recap

  • A brute-force attack simply tries many passwords against a login endpoint, no database access or code vulnerability required.
  • Correct hashing (Module 1) and correct credential-checking logic don’t defend against this at all, they protect a different scenario, a leaked database.
  • This is one of the most common real-world attacks against any public login endpoint, the next lesson covers the actual defense.

Next lesson: rate limiting, slowing repeated requests down enough to make this attack impractical.