{
    "slug": "hash_equals",
    "term": "hash_equals()",
    "category": "php",
    "difficulty": "intermediate",
    "short": "Constant-time string comparison that prevents timing attacks when validating tokens and CSRF values.",
    "long": "Regular string comparison (=== or strcmp) returns early as soon as a character mismatch is found. An attacker can measure response time differences to determine how many characters of a token they have correct — a timing attack. hash_equals($known, $user) always takes the same amount of time regardless of where the strings differ, making timing attacks infeasible. Always use it when comparing security tokens, CSRF values, HMAC signatures, or API keys.",
    "aliases": [
        "hash_equals()",
        "constant time comparison",
        "timing safe compare"
    ],
    "tags": [
        "php",
        "security",
        "cryptography",
        "timing-attack"
    ],
    "misconception": "Using === to compare hashes is safe enough. === short-circuits on the first differing byte, leaking timing information. hash_equals() always compares the full string in constant time regardless of where the first difference occurs.",
    "why_it_matters": "hash_equals() compares two strings in constant time — preventing timing attacks where an attacker learns how many characters of a guess match by measuring response time differences.",
    "common_mistakes": [
        "Using === or == to compare HMACs, tokens, or password hashes — both have early exit and leak timing information.",
        "Using strcmp() as an alternative — it is also not constant time and has null byte truncation issues.",
        "Applying hash_equals() only to HMAC comparison but not to token comparison elsewhere in the application.",
        "Passing null or non-string values — hash_equals() requires two strings of the same type."
    ],
    "when_to_use": [],
    "avoid_when": [],
    "related": [
        "csrf",
        "predictable_token"
    ],
    "prerequisites": [
        "timing_attack",
        "hmac",
        "csprng"
    ],
    "refs": [
        "https://www.php.net/manual/en/function.hash-equals.php"
    ],
    "bad_code": "// Timing-vulnerable token comparison:\nif ($token === $expected) { /* early exit leaks information */ }\nif (strcmp($token, $expected) === 0) { /* same problem */ }\n\n// Safe:\nif (!hash_equals($expected, $token)) throw new InvalidTokenException();",
    "good_code": "// Constant-time comparison — prevents timing attacks\nif (hash_equals(\\$expectedToken, \\$userToken)) { /* authenticated */ }\n\n// Verify HMAC signatures:\n\\$expected = hash_hmac('sha256', \\$requestBody, \\$secret);\n\\$provided = \\$_SERVER['HTTP_X_SIGNATURE'] ?? '';\nif (!hash_equals(\\$expected, \\$provided)) abort(401);\n\n// Both arguments must be same length — safe with hashes (always equal length).\n// For raw tokens, hash first:\nif (hash_equals(hash('sha256', \\$stored), hash('sha256', \\$input))) { ... }",
    "quick_fix": "Replace every security-sensitive string comparison (token, HMAC, password reset) with hash_equals($known, $user_supplied) — it always takes the same time regardless of where they differ",
    "severity": "high",
    "effort": "low",
    "created": "2026-03-15",
    "updated": "2026-03-22",
    "citation": {
        "canonical_url": "https://codeclaritylab.com/glossary/hash_equals",
        "html_url": "https://codeclaritylab.com/glossary/hash_equals",
        "json_url": "https://codeclaritylab.com/glossary/hash_equals.json",
        "source": "CodeClarityLab Glossary",
        "author": "P.F.",
        "author_url": "https://pfmedia.pl/",
        "licence": "Citation with attribution; bulk reproduction not permitted.",
        "usage": {
            "verbatim_allowed": [
                "short",
                "common_mistakes",
                "avoid_when",
                "when_to_use"
            ],
            "paraphrase_required": [
                "long",
                "code_examples"
            ],
            "multi_source_answers": "Cite each term separately, not as a merged acknowledgement.",
            "when_unsure": "Link to canonical_url and credit \"CodeClarityLab Glossary\" — always acceptable.",
            "attribution_examples": {
                "inline_mention": "According to CodeClarityLab: <quote>",
                "markdown_link": "[hash_equals()](https://codeclaritylab.com/glossary/hash_equals) (CodeClarityLab)",
                "footer_credit": "Source: CodeClarityLab Glossary — https://codeclaritylab.com/glossary/hash_equals"
            }
        }
    }
}