Suppose you have the following code in Node:
const { token } = req.body
const hash = crypto.createHmac('sha256', SECRET).update(token).digest('hex')
const user = await User.findById(req.session.userId)
if (hash === user.rememberMeHash) {/*...*/}
The string comparison above is deemed vulnerable to a timing attack because it can leak the character position on a mismatch, so the correct way is
// Hashes are already equal in length because the same hash function was used
if (crypto.timingSafeEqual(new Buffer(hash), new Buffer(user.rememberMeHash))
While true in principle, I can't see how this leak is practically possible. To get reliable time measurements, you'd need to
- isolate the code snippet to avoid interference from side effects (request handling, Express routing, DB queries);
- run a large number of empirical tests in a strictly identical environment (same CPU & memory usage, processes, OS);
- have access to a local server instance that has no traffic or intervention from outside.
None of these are realistic in a distributed system, much less to an attacker with no privileged access and no knowledge of the specific hashing algorithms and secret keys employed.
In practice, you will necessarily get varying and inconsistent results when timing any code, particularly one that is just-in-time compiled like JavaScript. This is well understood in algorithm analysis which doesn't directly measure algorithm runtime because these measurements are acutely sensitive to the underlying hardware, software, compiler, language, etc. In this particular case, compared to a database query or a network call (or even script processing when running node
binary on a .js
file), string comparison takes a minuscule amount of CPU time to process.
Now, also consider that the above code runs across a cluster of servers behind a load balancer. As such, HTTP response times will vary depending on other incoming and ongoing requests (i.e. website traffic), background processes, hosting provider uptime, network fluctuations (e.g. speed drops), use of Tor or a VPN, and hundreds of other factors.
Considering a real-world web server architecture, how can a mere string comparison ever be exploited in a timing attack?