skip to content

Explain the SCRAM salted challenge-response handshake and why it resists credential theft better than PLAIN over SASL_SSL.

level: seniorimportance: should knowfreq 40%

answer

  1. 4 messages: client-first, server-first, client-final, server-final
  2. PBKDF2(password,salt,iters) -> SaltedPassword
  3. broker stores StoredKey=H(ClientKey) + ServerKey
  4. ClientProof = ClientKey XOR ClientSignature; replay-proof via nonces
  5. ServerSignature = mutual auth; password never on wire

basics

~20 s

In SCRAM the client and server exchange nonces; the client derives a salted PBKDF2 key and sends a proof, never the password. The broker stores only StoredKey/ServerKey, so even a server breach or absent TLS doesn't directly leak the password.

solid answer

~50 s

SCRAM (RFC 5802) runs a four-message handshake. The client sends client-first with its username and a client nonce. The server replies with the combined nonce, the user's salt, and iteration count. The client computes SaltedPassword = PBKDF2(password, salt, iterations), then ClientKey = HMAC(SaltedPassword,'Client Key'), StoredKey = H(ClientKey), and a ClientProof from the auth message, sending the proof but never the password. The server, holding only StoredKey and ServerKey, recovers ClientKey from the proof, hashes it, and checks it equals StoredKey; it returns a ServerSignature so the client can authenticate the server too (mutual). Because the wire carries only nonces and proofs, capturing traffic doesn't reveal the password, and the server's stored material can't be replayed as a password elsewhere. PLAIN, by contrast, puts the cleartext password on the wire — safe only as long as TLS holds; a TLS misconfig, terminated proxy, or downgraded listener exposes it. SCRAM also defends against server-side credential reuse and adds mutual authentication.

go deeper

for a junior

Know at a high level: SCRAM proves the password without sending it; PLAIN sends it.

for a middle

Describe the nonce exchange and that only hashes are stored, plus replay protection.

for a senior

Walk the four-message flow, PBKDF2/HMAC derivations, StoredKey/ServerKey, and ClientProof verification.

for a principal

Reason about breach blast-radius (verifier theft), iteration tuning, mutual auth, and when SCRAM-over-SSL vs OAUTHBEARER/mTLS is the right architectural choice.

## Why challenge-response matters With PLAIN, the password itself is the thing sent. Its entire security rests on TLS confidentiality. If TLS is misconfigured, terminated at a proxy that logs payloads, or the listener is accidentally `SASL_PLAINTEXT`, the password is exposed and reusable. SCRAM is designed so that **no party ever transmits or persistently stores the cleartext password**. ## The SCRAM message flow (RFC 5802) Four messages, named after their content: 1. **client-first-message**: `n,,n=alice,r=<clientNonce>` — username plus a random client nonce. 2. **server-first-message**: `r=<clientNonce+serverNonce>,s=<salt>,i=<iterations>` — server appends its own nonce, and reveals the user's salt and iteration count (these are not secret). 3. **client-final-message**: `c=biws,r=<combinedNonce>,p=<ClientProof>` — the proof. 4. **server-final-message**: `v=<ServerSignature>` — proves the server also knew the verifier (mutual auth). ## The cryptography Let H = the hash (SHA-256 or SHA-512), HMAC = keyed hash. - `SaltedPassword = PBKDF2(password, salt, iterations)` — slow, salted derivation; the salt prevents rainbow tables, iterations slow brute force. - `ClientKey = HMAC(SaltedPassword, "Client Key")` - `StoredKey = H(ClientKey)` ← **this is what the broker stores** - `ServerKey = HMAC(SaltedPassword, "Server Key")` ← **also stored** - `AuthMessage = client-first-bare + "," + server-first + "," + client-final-without-proof` - `ClientSignature = HMAC(StoredKey, AuthMessage)` - `ClientProof = ClientKey XOR ClientSignature` ← sent on the wire - Server verifies: it computes `ClientSignature` (it has StoredKey and AuthMessage), recovers `ClientKey = ClientProof XOR ClientSignature`, and checks `H(ClientKey) == StoredKey`. - `ServerSignature = HMAC(ServerKey, AuthMessage)` ← returned for mutual auth. ## Why this resists credential theft better than PLAIN 1. **Nothing reusable on the wire**: an eavesdropper sees nonces, salt, iterations, and a proof bound to this session's nonces. It cannot be replayed (fresh nonces each session) and is not the password. 2. **Server breach is degraded, not catastrophic**: the broker stores StoredKey/ServerKey, not the password. An attacker who steals these can impersonate the user *to that cluster* (StoredKey is a verifier) but cannot trivially recover the password to reuse elsewhere, and would need an offline PBKDF2 brute-force (slowed by iterations) to get the password. 3. **Mutual authentication**: ServerSignature lets the client verify the server, hindering a rogue broker. 4. **Independent of TLS for password secrecy**: SCRAM keeps the password off the wire even if TLS fails — though you should still use SASL_SSL so data and the salt/proof exchange ride inside encryption. ## Limits / honest caveats - StoredKey is a **verifier**: stealing it from the broker lets an attacker authenticate to *this* cluster without the password. So SCRAM is not 'breach-proof' — it limits blast radius and prevents password reuse elsewhere. - The client still holds the cleartext password locally to compute the proof. - Higher `iterations` increase brute-force cost but add CPU per login. ## One-line contrast PLAIN = 'send the password, trust TLS.' SCRAM = 'prove you know the password without sending it, and let the server prove it too.'

  • If an attacker steals the SCRAM StoredKey/ServerKey from broker metadata, what can they do?
    StoredKey is a verifier, so they can impersonate that user to that specific cluster. They cannot directly read the password (would need an offline PBKDF2 brute-force, slowed by iterations) and so generally can't reuse it on other systems. This limits blast radius compared to a stolen cleartext password.
  • What stops a captured SCRAM ClientProof from being replayed?
    The proof is bound to fresh client and server nonces in the AuthMessage for that session. A replayed proof won't match the new server nonce, so the server rejects it.
  • Does SCRAM make TLS unnecessary?
    No. SCRAM only protects the password and authenticates; it does not encrypt data, ACL responses, or guarantee confidentiality. Run SCRAM over SASL_SSL so traffic is encrypted and to prevent active downgrade/MITM on the rest of the session.

saying these in an interview costs you the question

  • Claiming SCRAM is 'unbreakable' even if the broker store is stolen — StoredKey is a usable verifier for that cluster
  • Saying SCRAM removes the need for TLS
  • Claiming the password is sent (just hashed) — it is never sent
  • Forgetting nonces and thus the replay protection / mutual auth

context