Understanding timing attacks and why constant-time comparison matters
# Why Your Password Comparison is Leaking Secrets
Ever written code like this?
“`java
return storedPassword.equals(providedPassword);
“`
It looks harmless, but it has a critical security flaw. Let me explain.
## The Problem with String.equals()
Java’s `String.equals()` returns `false` the moment it finds the first mismatched character:
“`java
while (n– != 0) {
if (v1[i] != v2[i])
return false; // ⚠️ EARLY EXIT!
i++;
}
“`
This means:
– `”secret”` vs `”aaaaaa”` → fails at index 0 (fast)
– `”secret”` vs `”saaaaa”` → fails at index 1 (slower)
– `”secret”` vs `”seaaaa”` → fails at index 2 (even slower)
**An attacker can measure response times to guess passwords character by character!**
## How Timing Attacks Work
| Guess | Match Length | Response Time |
|——-|————–|—————|
| `axxxx` | 0 chars | ~100ns |
| `sxxxx` | 1 char | ~120ns |
| `sexxx` | 2 chars | ~140ns |
| `secxx` | 3 chars | ~160ns |
By running thousands of attempts and measuring tiny time differences, attackers can recover your passwords without ever seeing them.
## The Fix: Constant-Time Comparison
“`java
private boolean constantTimeEquals(String a, String b) {
byte[] aBytes = a.getBytes(StandardCharsets.UTF_8);
byte[] bBytes = b.getBytes(StandardCharsets.UTF_8);
if (aBytes.length != bBytes.length) {
return false;
}
int result = 0;
for (int i = 0; i < aBytes.length; i++) {
result |= aBytes[i] ^ bBytes[i];
}
return result == 0;
}
“`
**Key difference:** This loop ALWAYS runs through ALL characters. No early exit = no timing leak.
## Built-in Alternatives
Most languages provide secure comparison utilities:
**Java:**
“`java
MessageDigest.isEqual(aBytes, bBytes);
“`
**Node.js:**
“`javascript
crypto.timingSafeEqual(Buffer.from(a), Buffer.from(b));
“`
**Python:**
“`python
hmac.compare_digest(a, b)
“`
**PHP:**
“`php
hash_equals($known, $user_input);
“`
## When to Use It
✅ **Always use constant-time comparison for:**
– Passwords
– API keys
– Session tokens
– Any authentication credential
❌ **Regular equals is fine for:**
– Non-sensitive data
– Public information
## Key Takeaway
Security isn’t just about what your code does—it’s about what it reveals while doing it.
Next time you compare credentials, remember: `String.equals()` is fast, but it talks too much.
—
*Further reading: [OWASP Timing Attack](https://owasp.org/www-community/attacks/Timing_attack) | [CWE-208](https://cwe.mitre.org/data/definitions/208.html)*