New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
CompareStrings is not timing safe #720
Comments
It is indeed difficult to write a timing-safe code handling strings of varying length. But if we short-circuit immediately after encountering unequal lengths. This will, however, probably leak the length of the known string. This should be fine as the attacker knows the length of the known string anyway. String comparison implementation in Java and PHP exhibit this behaviour. |
This has been discussed a few times before in the history of this project (GH-13 and GH-266), but basically it boils down to bcrypt isn't susceptible to timing attacks like you're describing. It basically boils down to the comparison function compares hashes: https://github.com/kelektiv/node.bcrypt.js/blob/master/src/bcrypt_node.cc#L338 You can see that we do hash the value passed in before running the comparison. We couldn't do it any other way anyway since we can't reverse the hash in the first place. Also, here is a more detailed discussion related to this topic @ bcrypt-ruby/bcrypt-ruby#43 Does that help? |
Yup that makes sense. I actually stumbled across this because a member of my team was using a comparison with an empty hash to try and prevent leaking to an attacker whether an authentication failure was due to the user not existing or an incorrect password. The pseudo-code for what they were doing is something like:
Ignoring the many other obvious places where the above code leaks information through timing (database access, etc) - I assume this isn't a supported feature of the library? I doubted it was which was part of the reason I was digging into the code in the first place. If this isn't something that the library supports then it might be worth just using a normal string comparison function and removing the claim that the design of the function prevents timing attacks? |
@AndrewCarterUK yea. I agree with that. There was discussion very early on about changes to prevent timing attacks, and some work done to try to make the comparator be "constant time". But, once we realized that bcrypt wasn't actually susceptible, we stopped focusing on that. We get enough of these that it makes sense to put something, like what I posted above, in the readme. So I'll make a couple of those changes. |
Updated the readme with some notes related to timing attacks and the comparison function used in the bcrypt module.
The prior code didn't provide constant time comparison and it wasn't necessary anyway. Removed in favor of strcmp. Kept the wrapper function to maintain api consistency. Signed-off-by: Nick Campbell <nicholas.j.campbell@gmail.com>
Updated the readme with some notes related to timing attacks and the comparison function used in the bcrypt module.
The prior code didn't provide constant time comparison and it wasn't necessary anyway. Removed in favor of strcmp. Kept the wrapper function to maintain api consistency. Signed-off-by: Nick Campbell <nicholas.j.campbell@gmail.com>
Updated the readme with some notes related to timing attacks and the comparison function used in the bcrypt module.
The prior code didn't provide constant time comparison and it wasn't necessary anyway. Removed in favor of strcmp. Kept the wrapper function to maintain api consistency. Signed-off-by: Nick Campbell <nicholas.j.campbell@gmail.com>
Updated the readme with some notes related to timing attacks and the comparison function used in the bcrypt module.
The prior code didn't provide constant time comparison and it wasn't necessary anyway. Removed in favor of strcmp. Kept the wrapper function to maintain api consistency. Signed-off-by: Nick Campbell <nicholas.j.campbell@gmail.com>
I've created a script for testing the CompareStrings function as after glancing over it I suspected that it wasn't a constant time function.
The results from my script suggest that my suspicions were correct and that the function does not execute in a constant time.
The graph below shows the average time to execute 100 million comparisons, where
Z
is a zero length string andA
andB
are different strings of the same length (26 chars).As you can see, comparisons with a different length of string have very different execution times. Even with the same length of string, comparisons of matching strings run faster than comparisons of different strings.
I've annotated the function in question below, to show where I understand that it might be leaking timing information.
One fundamental component to writing timing safe code, is ensuring that the same instructions are executed regardless of the input. Comparison statements such as
if
and?
are almost always not timing safe, as they result in different instructions executed dependent on the outcome of the comparison. Even when this is done, execution may be dependent on input as processor caches and branch prediction can also have a large impact on execution speed.It's very difficult to get a timing safe comparison algorithm that can handle strings of different lengths. The only approach I can suggest is hashing the strings before comparing them, and even then there are other flaws associated with this approach.
I'm not a security expert (and I would seek the advice on one for a topic as important as this on a popular library), but a function such as the one below appears to have less variation on execution time (though it still have some). The downside of course is that it requires the strings to be of the same length, but this could potentially be mitigated by passing the inputs through a timing safe hash function beforehand.
The text was updated successfully, but these errors were encountered: