DEV Community

Cover image for Authentication Security Deep Dive: From Brute Force to Salted Hashing (With Java Examples)
Sanjay Ghosh
Sanjay Ghosh

Posted on

Authentication Security Deep Dive: From Brute Force to Salted Hashing (With Java Examples)

What if I told you that even if you hash passwords, an attacker might still crack them in seconds?

Authentication is one of the most critical parts of any applicationโ€”and also one of the most misunderstood.

In this post, weโ€™ll think like an attacker, break insecure implementations using Java examples, and then progressively strengthen our defenses using hashing and salting.
If youโ€™ve ever stored a password using only hashing, your system may still be vulnerable.

๐Ÿง  1. Why Authentication Security Matters

When authentication fails, everything fails:

  • Account takeover
  • Data breaches
  • Privilege escalation

To build secure systems, we must first understand how attackers operate.

โš”๏ธ 2. How Attackers Break Authentication

(i). Brute Force Attack

Attacker tries all possible passwords until one works.
๐Ÿ‘‰ Works because:

  • Users choose weak passwords
  • Systems donโ€™t limit attempts

(ii). Dictionary Attack

Instead of all combinations, attacker uses a list of common passwords:
123456
password
admin
welcome123

(iii). Rainbow Table Attack

Attacker precomputes hashes:
password โ†’ hash1
admin โ†’ hash2

Then instantly matches stolen hashes.
๐Ÿ‘‰ Extremely fast if no salt is used

(iv). Session Attacks (brief)

Focus on hijacking authenticated sessions (cookies, tokens).
๐Ÿ‘‰ Important, but outside this blogโ€™s main focus.

๐Ÿ”ด 3. Thinking Like an Attacker: Breaking Weak Authentication

3.1 Brute Force Simulation (Java)

package com.auth;

public class BruteForceDemo {

    public static void main(String[] args) {

        String actualPassword = "1234";

        for (int i = 0; i <= 9999; i++) {
            String guess = String.format("%04d", i);

            System.out.println("Trying: " + guess);

            if (guess.equals(actualPassword)) {
                System.out.println("==> Password found: " + guess);
                break;
            }
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

๐Ÿ‘‰ This works because:

  • Password is short and predictable
  • No rate limiting

3.2 Hashing Alone is NOT Enough

Letโ€™s say system stores:
hash(password)
Java Example

package com.auth;

import java.security.MessageDigest;

public class HashAttackDemo {

    public static String hash(String input) throws Exception {
        MessageDigest md = MessageDigest.getInstance("SHA-256");
        byte[] digest = md.digest(input.getBytes());

        StringBuilder hex = new StringBuilder();
        for (byte b : digest) {
            hex.append(String.format("%02x", b));
        }
        return hex.toString();
    }

    public static void main(String[] args) throws Exception {

        String storedHash = hash("password");

        String[] guesses = {"123456", "password", "admin"};

        for (String guess : guesses) {
            if (hash(guess).equals(storedHash)) {
                System.out.println("==> Cracked: " + guess);
            }
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

๐Ÿ‘‰ Even though password is hashed, attacker can still:

  • Hash guesses
  • Compare results

3.3 Rainbow Table Attack (Precomputation)

package com.auth;

import java.security.MessageDigest;
import java.util.HashMap;
import java.util.Map;

public class RainbowTableDemo {

    public static String hash(String input) throws Exception {
        MessageDigest md = MessageDigest.getInstance("MD5");
        byte[] digest = md.digest(input.getBytes());

        StringBuilder hex = new StringBuilder();
        for (byte b : digest) {
            hex.append(String.format("%02x", b));
        }
        return hex.toString();
    }

    public static void main(String[] args) throws Exception {

        String[] passwords = {"123456", "password", "admin"};

        Map<String, String> table = new HashMap<>();

        for (String pwd : passwords) {
            table.put(hash(pwd), pwd);
        }

        String stolenHash = hash("password");

        if (table.containsKey(stolenHash)) {
            System.out.println("==> Instantly cracked: " + table.get(stolenHash));
        }
    }
}

Enter fullscreen mode Exit fullscreen mode

๐Ÿ‘‰ No guessing needed โ€” just lookup.

๐Ÿ›ก๏ธ 4. Why SALT Changes Everything

4.1 Why SALT is Needed


Problem:
password โ†’ same hash everywhere
Solution:
hash(password + salt)
๐Ÿ‘‰ Makes each hash unique
4.2 SALT Implementation (Java)

package com.auth;

import java.security.MessageDigest;
import java.security.SecureRandom;
import java.util.Base64;

public class SaltedHashDemo {

    public static String generateSalt() {
        byte[] salt = new byte[16];
        new SecureRandom().nextBytes(salt);
        return Base64.getEncoder().encodeToString(salt);
    }

    public static String hash(String password, String salt) throws Exception {
        MessageDigest md = MessageDigest.getInstance("SHA-256");
        byte[] digest = md.digest((password + salt).getBytes());

        StringBuilder hex = new StringBuilder();
        for (byte b : digest) {
            hex.append(String.format("%02x", b));
        }
        return hex.toString();
    }

    public static void main(String[] args) throws Exception {

        String password = "password";
        String salt = generateSalt();

        String hashed = hash(password, salt);

        System.out.println("Salt: " + salt);
        System.out.println("Hash: " + hashed);
    }
}

Enter fullscreen mode Exit fullscreen mode

4.3 How SALT Breaks Rainbow Attacks

password + salt1 โ†’ hash1
password + salt2 โ†’ hash2

๐Ÿ‘‰ Same password โ‰  same hash
๐Ÿ‘‰ Rainbow tables become useless

๐Ÿ”ด 5. Attacker vs SALT

5.1 Attacking Salted Hashes (Java)

package com.auth;

import java.security.MessageDigest;

public class SaltedAttackDemo {

    public static String hash(String password, String salt) throws Exception {
        MessageDigest md = MessageDigest.getInstance("SHA-256");
        byte[] digest = md.digest((password + salt).getBytes());

        StringBuilder hex = new StringBuilder();
        for (byte b : digest) {
            hex.append(String.format("%02x", b));
        }
        return hex.toString();
    }

    public static void main(String[] args) throws Exception {

        String salt = "randomSalt123";
        String storedHash = hash("password", salt);

        String[] dictionary = {"123456", "password", "admin"};

        for (String guess : dictionary) {
            if (hash(guess, salt).equals(storedHash)) {
                System.out.println("==> Cracked even with salt: " + guess);
            }
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

๐Ÿ‘‰ Salt does NOT stop guessing โ€” only slows it down.

5.2 Cost Explosion

Without salt:
1M guesses โ†’ cracks many users
With salt:
1M users ร— 1M guesses = 1 trillion operations

Source Code

All source files are available on GitHub:
Github source codes

๐Ÿ‘‰ This is where salt becomes powerful.

โš ๏ธ 6. What SALT Does NOT Solve

  • Weak passwords (still crackable)
  • Fast hashing (SHA-256 is too fast)
  • GPU-based attacks

๐Ÿ‘‰ SALT makes attacks harderโ€”but not impossible.
Attackers can still:

  • Perform brute force attacks
  • Use GPUs to compute hashes at scale
  • Target weak passwords

This is why modern systems go beyond

๐Ÿš€ Final Defense: Modern Password Hashing
Use:

Why:

  • Built-in salt
  • Slow hashing (costly per attempt)
  • Resistant to GPU attacks

๐Ÿง  7.Conclusion

Authentication security evolves like this:
Plain text โ†’ completely broken
Hash only โ†’ still vulnerable
Salted hash โ†’ better
Salt + slow hashing โ†’ strong defense

๐Ÿ‘‰ Security is not about making attacks impossible,
๐Ÿ‘‰ Itโ€™s about making them economically infeasible.

๐Ÿ’ก 8.Final Thought

Think like an attacker:

  • Can I guess this password?
  • Can I reuse work?
  • Can I scale this attack?

Good security doesnโ€™t make attacks impossibleโ€”it makes them impractical.

As a developer, your goal isnโ€™t to stop attackers completely, but to ensure that breaking your system is simply not worth the effort.

Top comments (0)