← CodeClarityLab Home
Browse by Category
+ added · updated 7d
← Back to glossary

Timing Attack

security CWE-208 OWASP A2:2021 CVSS 5.9 PHP 5.6+ Advanced

Also Known As

time-based side channel timing side channel response time attack

TL;DR

Measuring how long a comparison takes reveals information about secret values — use hash_equals() to prevent it.

Explanation

A timing attack exploits the fact that string comparison operators (===, strcmp) return early on the first mismatched character, so comparing a correct token takes slightly longer than an incorrect one. By making thousands of requests and measuring response times, an attacker can determine the correct token one character at a time. hash_equals() prevents this by always taking the same time regardless of where the strings differ. Always use it when comparing tokens, HMAC signatures, and CSRF values.

How It's Exploited

# Measure response time for different token prefixes
# Correct prefix → takes slightly longer → reveals chars one by one
# Requires many requests and statistical analysis but works against == comparison

Common Misconception

Timing differences of microseconds are too small for attackers to measure over the internet. Statistical timing attacks average thousands of measurements to filter out network jitter — even millisecond differences in HMAC comparison are exploitable remotely.

Why It Matters

Even microsecond differences in response time can reveal whether a guessed secret is correct, allowing an attacker to recover a password or token character by character.

Common Mistakes

  • Using === to compare password hashes, HMACs, or tokens — exits early on first byte mismatch.
  • Using strcmp() which also short-circuits and has additional issues with null bytes.
  • Not using hash_equals() in PHP for all secret comparisons.
  • Applying timing-safe comparison only to the final comparison but not to intermediate validation steps.

Avoid When

  • Never use === or == to compare HMAC signatures, API tokens, or password hashes — both short-circuit on the first differing byte.
  • Do not compare secrets with strcmp() or strncmp() — they are not constant-time.

When To Use

  • Use hash_equals() for all security-sensitive string comparisons — it runs in constant time regardless of where strings differ.
  • Use password_verify() for password checks — it uses constant-time comparison internally.

Code Examples

✗ Vulnerable
// === exits on first mismatch — reveals partial token via timing
if (\$_GET['token'] === \$secretToken) { grantAccess(); }
✓ Fixed
// hash_equals() — constant-time comparison regardless of where mismatch occurs
if (hash_equals(\$secretToken, \$_GET['token'] ?? '')) {
    grantAccess();
}

// For password verification — always use password_verify (also constant-time)
if (password_verify(\$input, \$storedHash)) { /* authenticated */ }

// Timing-safe HMAC comparison for API signatures
\$expected = hash_hmac('sha256', \$requestBody, \$secret);
\$provided = \$_SERVER['HTTP_X_SIGNATURE'] ?? '';
if (!hash_equals(\$expected, \$provided)) { abort(401); }

Added 15 Mar 2026
Edited 31 Mar 2026
Views 43
Rate this term
No ratings yet
🤖 AI Guestbook educational data only
| |
Last 30 days
0 pings F 0 pings S 0 pings S 0 pings M 0 pings T 0 pings W 0 pings T 1 ping F 0 pings S 1 ping S 1 ping M 0 pings T 1 ping W 0 pings T 2 pings F 0 pings S 0 pings S 0 pings M 0 pings T 1 ping W 0 pings T 1 ping F 0 pings S 0 pings S 0 pings M 0 pings T 0 pings W 0 pings T 1 ping F 0 pings S
No pings yet today
Amazonbot 9 Perplexity 7 ChatGPT 6 Google 5 Unknown AI 4 Ahrefs 2
crawler 31 crawler_json 1 pre-tracking 1
DEV INTEL Tools & Severity
🟠 High ⚙ Fix effort: Low
⚡ Quick Fix
Replace all security-sensitive string comparisons with hash_equals($known, $user_input) — it always takes constant time
📦 Applies To
PHP 5.6+ web api cli
🔗 Prerequisites
🔍 Detection Hints
$token === $stored or $hmac == $computed in authentication or CSRF token verification context
Auto-detectable: ✓ Yes semgrep psalm
⚠ Related Problems
🤖 AI Agent
Confidence: High False Positives: Low ✓ Auto-fixable Fix: Low Context: Line
CWE-208

✓ schema.org compliant