Colin Percival announced an interesting bug back in December in howAmazon Web Services signs data. Amazon allows users of their APIs (e.g., EC2 and SimpleDB) to authenticate requests by applying an HMAC. This is supposed to ensure the request was unmodified after the sender created it; however, there was a subtle flaw that allowed an attacker to forge requests in certain circumstances.
An HMAC works by applying a cryptographic hash algorithm to the user’s data and a secret key. Another party who knows the same secret key can perform the same calculation. If the HMAC results match, the data has not been modified. The problem lies in the lack of structure Amazon applied to the data, resulting in exploitable ambiguity. You can see Colin’s advisory for more details about how this can be exploited. See also the function signParameters() in the client code, AmazonEC2Client.java, for all three versions of this function.
To prepare a URL to be authenticated in AWS-Signature v1, the API caller concatenates all the key/value pairs into a single string (key1 || value1 || key2 || value2). Then, the caller calculates the HMAC of this value and attaches it to the original API request as the “Signature=” key. The HMAC is supposed to authenticate this request, proving that the sender originated the request and that it had not been modified in transit.
It’s pretty obvious that this lack of structure results in an ambiguous interpretation. The HMACs of the following URLs are identical:
As long as the attacker can change the value of any tag in the request and observe the resulting HMAC, he can later add any number of bad keys and bad values and resubmit the request with the same HMAC. The fix in AWS-Signature v2 is to add back various delimiters between the key/value pairs before calculating the URL’s HMAC.
There’s a variant of this attack that even AWS-Signature v2 does not appear to address. If an attacker can observe a single signed request, that request can be resubmitted any number of times. Thus, an API call like “credit account $10” could be repeated any number of times. Of course, using SSL for the request would prevent this attack, and it’s likely that users would send most financially-related messages over SSL. However, given that this protocol is intended to be secure over plain HTTP, it’s possible some users trust it to ensure message uniqueness in addition to integrity protection.
I’ve observed this kind of flaw before in other systems, including specifications for single-sign-on cookies. Vendors that specify their own signature format should get a review of their design to be certain they strictly validate the structure for any values that they sign.