A strong answer
Start with the attack this prevents. A hash table is only fast while keys spread across its slots. If an attacker knows the hash function, they can generate thousands of strings that all have the same hash (hash flooding). Every one of them lands in the same slot, so each insert has to walk past all the earlier ones, and n inserts cost O(n²) work instead of O(n). This is called hash flooding.
It is a realistic attack because servers build hash tables from input they don't control: form fields, JSON object keys, HTTP headers and query parameters. In 2011, researchers showed that a single crafted request could keep a server busy for minutes on many popular web platforms.
Randomizing the hash takes away the attacker's knowledge. The language mixes a secret random key into every string hash. Python chooses its key when the process starts; Go and Rust choose a key for each new map. Within one table the hash is still deterministic, which is all the table needs. The attacker can't see the key, so they can't work out which strings will collide.
A key only helps if the hash function mixes it in thoroughly, so these languages pair it with a hash built for the job. Python and Rust use SipHash, which was designed to defend hash tables against flooding while staying fast on short keys. Go uses a seeded hash built on the processor's AES instructions where they are available.
The price is that hash values change from run to run, so a program must never store them or depend on the iteration order they produce.
What the interviewer is listening for
- The attack: colliding keys turn O(1) operations into O(n), and n inserts into O(n²).
- Why it is realistic: servers put untrusted input into hash tables.
- How the defense works: a secret key, per process or per table, that the attacker can't see.
- The trade-off: hashes are no longer stable between runs.
Common mistakes
- Saying the randomization makes hashes "more random" or spreads ordinary keys better. A good fixed hash already spreads ordinary keys; the defense is against an adversary who chooses the keys.
- Proposing a cryptographic hash such as SHA-256 for every lookup. It would resist flooding, but it is far too slow for a hash table. SipHash exists because it is keyed and fast.
- Forgetting that Java took a different path. Its string hash is fixed by its specification, so Java limits the damage with tree bins instead.