secureEqual

Securely compares two digest representations while protecting against timing attacks. Do not use == to compare digest representations.

The attack happens as follows:

  1. An attacker wants to send harmful data to your server, which requires a integrity HMAC SHA1 token signed with a secret.
  2. The length of the token is known to be 40 characters long due to its format, so the attacker first sends "0000000000000000000000000000000000000000", then "1000000000000000000000000000000000000000", and so on.
  3. The given HMAC token is compared with the expected token using the == string comparison, which returns false as soon as the first wrong element is found. If a wrong element is found, then a rejection is sent back to the sender.
  4. Eventually, the attacker is able to determine the first character in the correct token because the sever takes slightly longer to return a rejection. This is due to the comparison moving on to second item in the two arrays, seeing they are different, and then sending the rejection.
  5. It may seem like too small of a difference in time for the attacker to notice, but security researchers have shown that differences as small as 20µs can be reliably distinguished even with network inconsistencies.
  6. Repeat the process for each character until the attacker has the whole correct token and the server accepts the harmful data. This can be done in a week with the attacker pacing the attack to 10 requests per second with only one client.

This function defends against this attack by always comparing every single item in the array if the two arrays are the same length. Therefore, this function is always O(n) for ranges of the same length.

This attack can also be mitigated via rate limiting and banning IPs which have too many rejected requests. However, this does not completely solve the problem, as the attacker could be in control of a bot net. To fully defend against the timing attack, rate limiting, banning IPs, and using this function should be used together.

bool
secureEqual
(
R1
R2
)
(
R1 r1
,
R2 r2
)

Parameters

r1 R1

A digest representation

r2 R2

A digest representation

Return Value

Type: bool

true if both representations are equal, false otherwise

Examples

import std.digest.hmac : hmac;
import std.digest.sha : SHA1;
import std.string : representation;

// a typical HMAC data integrity verification
auto secret = "A7GZIP6TAQA6OHM7KZ42KB9303CEY0MOV5DD6NTV".representation;
auto data = "data".representation;

auto hex1 = data.hmac!SHA1(secret).toHexString;
auto hex2 = data.hmac!SHA1(secret).toHexString;
auto hex3 = "data1".representation.hmac!SHA1(secret).toHexString;

assert( secureEqual(hex1[], hex2[]));
assert(!secureEqual(hex1[], hex3[]));

See Also

Meta