Web security
What are Timing Attacks and How to Prevent them using Node.js?
I wasn’t aware of that security breach until someone demonstrated to me that my code was vulnerable.
When playing with secret and network you might be tempted by doing a classic triple equality verification.
Imagine you have an API route that requires some header/payload with an API key to be accessible (ex: *4wyU1O!aSZECZXz$1NYymtGBX
).
We might have the following code:
// This is a Typescript file, body is a JSON object with given shape
function onRequest(body: {secret: string}) {
if(body.secret !== "*4wyU1O!aSZECZXz$1NYymtGBX") {
throw new AccessDeniedException();
}
// Do something else and be considered granted
}
At first glance, this code looks perfectly working, and in fact, it is working fundamentally. The real truth besides this code and its vulnerability and much more vicious.
Why is that? Let’s first dig into the purpose of a timing attack and the behavior of string comparison in Node.js.
What is a timing attack?
In cryptography, a timing attack is a side-channel attack in which the attacker attempts to compromise a cryptosystem by analyzing the time taken to execute cryptographic algorithms.
String comparison is a function that takes various times to process depending on input, therefore it is vulnerable to timing attacks.
In most cases, whenever your code, you don’t rely on external sensitive data, but when you compare external secrets provided by some end-users, like for an API key, you might be vulnerable.
How does the string comparison work in Node.js
When you use triple equality ===
the JavaScript engine will iterate through each letter and compare the characters at the same index. At first mismatch, it returns false.
This means the computation generally takes a little more time if it fails at later characters.
Using this technique we can detect a change in processing time when a good letter is a match, and we can move forward until we get the full string equality.
How to prevent a timing attack in Node.js?
To solve this issue of « brute-forcing » we need a comparison technique that takes the same time « Timing Safe » whatever there is an early mismatch on characters or not. Using a safe comparison function that will check for string length difference and compare all characters consistently all the time.
This way it roundly takes always the same time to compare two different strings.
In Node.js’ crypto
module, we have a timingSafeEqual
a function that fulfills this purpose here is an example of an implementation using a passport-js
strategy.