Just a quick update to say that I’ve now updated my reference implementation of OpenPGP signin to address the local and cross domain replay attack discussed in the post I made on Friday.
The spec has been modified to require the sign in signature to include a timestamp and the requested url. The addition of these allows a site to verify that the request is directed to the correct site, and that it is a fresh request.
Forming the signature
The signature is formed over a message payload containing:
- The current date and time in ISO8601 format, as produced by
date('c', time());
- Your profile URL
- The URL of the resource you’re requesting, which must be on the site you’re requesting it from.
Separated by a new line and/or whitespace.
Verifying the signature
Before verifying the signature, the plugin extracts the urls and the timestamp:
if (preg_match_all("/(https?:\/\/[^\s]+)/", $signature, $matches, PREG_SET_ORDER)) {
$user_id = $matches[0][0];
$request_url = $matches[1][0];
}
if (preg_match('/([0-9]{4}-?[0-9]{2}-?[0-9]{2}T[0-9]{2}:?[0-9]{2}:?[0-9]{2}[+-Z]?([0-9]{2,4}:?([0-9]{2})?)?)/',$signature, $matches))
$timestamp = strtotime($matches[0]);
Then checks that the $request_url
is local, and the timestamp is within 5 seconds of now.
If this is all you do, there still exists a short window of time where a replay would work for the same host. If an attacker were able to capture and replay the packet within 5 seconds to the same site, then at the moment they’d still be logged in. Unlikely, but it’s a mistake to underestimate an attacker’s abilities.
So, my implementation also converts the timestamp/request url/user triple into a nonce internally, and stores this against a user object for a minute or so. This lets us identify and throw away any packets that we have encountered previously.
Known issues and further discussion
Ok, so at the moment there still exists a replay vulnerability whereby if your attacker is attacking you from an automated node physically near you, they can take take advantage of a race condition and get their replay attack in before the legitimate packet makes the full round trip to the server.
Currently though, the only people we know to have the capability to do this are GCHQ and the NSA, and really the best counter to those guys would be to conduct the whole exchange over HTTPS (which is a good idea anyway).
That said, an implementation of this protocol should, when encountering a duplicate packet, destroy all sessions belonging to that user.