Add a constant-time string comparison function to defuse timing and type-juggling attacks
Summary:
There are two theoretical attacks possible against some of our comparisons, where we check if some user-provided hash matches some secret hash.
The first is a timing attack, which has been previously reported on HackerOne but which I can't demonstrate as feasible even given huge assumptions in favor of the attacker.
In this attack, the attacker provides a secret like "azzz", then "bzzz", then "czzz", etc. They observe how long the responses take. The secret with the correct first charater will take a nanosecond longer because the computer must do more work to compare two bytes intead of 1. By making billions (trillions? quadrillions?) of requests and using statistical methods, they can slowly figure out the secret string, at least in theory.
The second is a type-juggling attack, where the attacker provides "0" and hopes to hit a hash in the form "0e1239847934892" so PHP can do nonsense with the string comparison by casting it to a float. This is possible in theory but the window for it is time-bounded in all known cases (e.g., CSRF tokens have 1-hour windows decades or centuries apart, and the times can not be predicted).
Still, we can defuse these completely and make them impossible rather than merely impractical with bytewise, constant time comparisons.
These defuse the timing attack by always taking the same amount of time to compare strings (regardless of how many bytes they have in common) and defuse the type juggling attack by avoiding invocation of type juggling comparisons.
Test Plan: Added and executed unit tests.
Reviewers: chad
Reviewed By: chad
Differential Revision: https://secure.phabricator.com/D14025