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
Mojo::Util secure_compare still leaks timing information #1599
Comments
Note running tests on different machines (different Linux versions) and different versions of Perl, the timings are less consistent, but generally diff1 takes less time than diff5 or diff9 or same. |
Actually, this is bitwise or so it shouldn't short-circuit. Closing this as invalid, although I suspect there's something else going on that leads this to leak information about where the difference is. |
Running it locally here I don't get a meaningful difference. I wonder if you happened to have a lucky run. (By this I mean my results weren't ordered at all). |
I've run it many times on numerous machines, Perl 5.22.2, 5.28.1 and 5.30.3. I've found the following: diff1 is consistently less time than all others. Anyhow, I closed this when I realised that the ordering was not as consistent as it first appeared. Also, because it immediately returns when the two strings do not have equal length, then it is possible to guess how long the string is. (Keep adding a character to string, and time the compare, then look for the comparison that took the most time.) |
If the lengths are unequal, you could pad them and run them through the bitwise checker, problem is then unequal length strings will take more time rather than less. |
The purpose of the function is to avoid leaking information about a secret string to an attacker who is using the time it takes for the method to run. Because the function exits quickly when the string lengths are unequal, it makes it easy to for the attacker to guess how long the secret string is. |
If you appended a random length string to both values the problem would be mitigated, no? |
Isn't there a standard implementation for the function we can steal? |
I don't know who this is but a quick search found this and it seems sane: https://github.com/vadimdemedes/secure-compare/blob/master/index.js |
diff --git a/lib/Mojo/Util.pm b/lib/Mojo/Util.pm
index 630607490..4ee82b5e8 100644
--- a/lib/Mojo/Util.pm
+++ b/lib/Mojo/Util.pm
@@ -276,8 +276,8 @@ sub scope_guard { Mojo::Util::_Guard->new(cb => shift) }
sub secure_compare {
my ($one, $two) = @_;
- return undef if length $one != length $two;
- my $r = 0;
+ my $r = length $one != length $two;
+ $two = $one if $r;
$r |= ord(substr $one, $_) ^ ord(substr $two, $_) for 0 .. length($one) - 1;
return $r == 0;
}
|
That looks alright. In the POD you should not that the "secret" should be the second argument. |
I'll create a PR if you'd like. |
By immediately returning when the two strings are not the same length, the function allows an attacker to guess the length of the secret string using timing attacks. This change uses a fix by @jberger, based on [1]. This also u[pdates the documentation to emphasize that the secret string should be the second argument (although it's not critical). [1] https://github.com/vadimdemedes/secure-compare/blob/master/index.js
By immediately returning when the two strings are not the same length, the function allows an attacker to guess the length of the secret string using timing attacks. This change uses a fix by @jberger, based on [1]. This also updates the documentation to emphasize that the secret string should be the second argument (although it's not critical). [1] https://github.com/vadimdemedes/secure-compare/blob/master/index.js
By immediately returning when the two strings are not the same length, the function allows an attacker to guess the length of the secret string using timing attacks. This change uses a fix by @jberger, based on [1]. This also updates the documentation to emphasize that the secret string should be the second argument (although it's not critical). [1] https://github.com/vadimdemedes/secure-compare/blob/master/index.js
By immediately returning when the two strings are not the same length, the function allows an attacker to guess the length of the secret string using timing attacks. This change uses a fix by @jberger, based on [1]. This also updates the documentation to emphasize that the secret string should be the second argument (although it's not critical). [1] https://github.com/vadimdemedes/secure-compare/blob/master/index.js
By immediately returning when the two strings are not the same length, the function allows an attacker to guess the length of the secret string using timing attacks. This change uses a fix by @jberger, based on [1]. This also updates the documentation to emphasize that the secret string should be the second argument (although it's not critical). [1] https://github.com/vadimdemedes/secure-compare/blob/master/index.js
By immediately returning when the two strings are not the same length, the function allows an attacker to guess the length of the secret string using timing attacks. This change uses a fix by @jberger, based on [1]. This also updates the documentation to emphasize that the secret string should be the second argument (although it's not critical). [1] https://github.com/vadimdemedes/secure-compare/blob/master/index.js
Mojo::Util#secure_compare fix leak of string length #1599
Steps to reproduce the behavior
I would expect the cumulative or code to short-circuit comparisons once r is true.
I wrote a rudimentary benchmark:
It seems that the latter a difference occurs in a string, the longer the comparison takes:
So this does leak information about the strings.
Expected behavior
There should be no difference in the timing.
Actual behavior
The latter a difference occurs in a string, the longer the check takes.
The text was updated successfully, but these errors were encountered: