U2F is a two step process - you need to register the device first (through challenge-response process called ENROLLMENT), then you can use it by issuing authentication challenge (U2F authentication is NOT the same as user authentication, they labeled the process as ENROLLMENT - AUTH process).
During registration you receive several pieces of info, such as keyHandle, public key you use to verify future device responses and an attestation certificate so you can verify the device vendor.
The interesting part is this: when you challenge the u2f device to sign AUTHENTICATION request, what it does is keep a counter tied to your appId (the domain where the .js that deals with this is executed) and it produces encoded json which is signed by the device, using an EC private key.
The counter increases every time the device is challenged by that particular appId. The response is signed using the counter and a private key that's on the device (which you can't tamper with).
So, the phishing / mitm should have the value of private key and the moving part (counter) that's tied to a specific appId. That's difficult since it SHOULD do this during enrollment process and every subsequent authentication request.
What's important that not only does it protect against phishing but from replays too. Naturally, the u2f device isn't standalone responsible for this, the verifying server implementation is a crucial part of the process.
Disclaimer: I'm not affiliated by Yubico, but have implemented U2F (the dreaded js part and backend part) in 2015, several months after Chrome 38 has been released, the first version supporting u2f protocol.
Last time I checked (more than a year ago) most of the websites didn't care about the counter value.
(If you use a Ledger device for U2F and subsequently restore a new (or a reset) device from your private seed the counter will be reset. Trezor has the same issue but allows you to manually set the counter to work around it.)
I haven't got any info on websites caring about the counter value. It seems.. pointless to use U2F if you just disregard the counter value. You need to extract it from the response in order to construct the binary data to verify the signature. If one disregards the counter value, they can just outright drop the whole U2F.
> If one disregards the counter value, they can just outright drop the whole U2F.
It's not pointless. Disregarding the counter only enables replay attacks, that is: the attacker must previously have captured a challenge/response. The phishing resistance is still retained because it relies on the browser passing the origin to the u2f device and the browser can't be fooled by similar URLs while a human entering a TOTO token can.
U2F isn't as trivial to implement as RFC4226 OTP. It takes effort. Implementing the counter check is trivial. Disregarding the counter and stating "that only enables replays" is absolutely unacceptable. If one is so irresponsible to the point they're enabling a replay attack - then there's no excuse and no valid argument to support the use of U2F at all. If you (not YOU, personally) can't implement the protocol fully, don't half-ass it and plant mines. That's my take on it, and anyone who implements this protocol to secure people's accounts MUST (not SHOULD) think the same. There is NO excuse for deliberate irresponsibility.
During registration you receive several pieces of info, such as keyHandle, public key you use to verify future device responses and an attestation certificate so you can verify the device vendor.
The interesting part is this: when you challenge the u2f device to sign AUTHENTICATION request, what it does is keep a counter tied to your appId (the domain where the .js that deals with this is executed) and it produces encoded json which is signed by the device, using an EC private key.
The counter increases every time the device is challenged by that particular appId. The response is signed using the counter and a private key that's on the device (which you can't tamper with).
So, the phishing / mitm should have the value of private key and the moving part (counter) that's tied to a specific appId. That's difficult since it SHOULD do this during enrollment process and every subsequent authentication request.
What's important that not only does it protect against phishing but from replays too. Naturally, the u2f device isn't standalone responsible for this, the verifying server implementation is a crucial part of the process.
Disclaimer: I'm not affiliated by Yubico, but have implemented U2F (the dreaded js part and backend part) in 2015, several months after Chrome 38 has been released, the first version supporting u2f protocol.