> I don't think Webauthn guarantees that the site I'm authenticating to is the site I'm supposed to (though I may be wrong here, I didn't read into it too deeply). As far as I know it still relies on TLS for that, and regular phishing and typosquatting show that this is not airtight.

WebAuthn needs the DNS name of the site to exactly match. This isn't for humans, who think 1 and I are pretty similar, it's for a machine, which thinks they're different. Phishing and typosquatting don't get you google.example they get your google.comsecurityupdatelogin.example or goggle.example which do not match. Now, in principle you could attack the Ten Blessed Methods to get yourself a real, legitimate (albeit fraudulently obtained) certificate for the exact DNS name of a real popular site, but that's not easy, and indeed making it more difficult is a continuing focus of Web PKI work. Also, defenders can make it arbitrarily harder if they put work in.

I never tired of explaining the clever trick that makes this possible, so here goes (for the easy case of a cheap Security Key, something like an iPhone can do fancier tricks with more complicated explanations)

When you enroll at some.example, your Security Key is told we're enrolling at SHA256("some.example"). A button flashes and you push it. The Security Key picks a completely random public/private key pair. It uses the private key to sign a document, "Hello, I am this Security Key, I checked a human was present" and it encrypts the private key with its own symmetric key and with that SHA256("some.example") parameter as "Extra data" in an AEAD (Authenticated Encryption, Extra Data) cipher to produce a large opaque blob it will claim is a "random identifier". It sends the public key, the "random identifier" and the signed message back to your web browser. You are enrolled.

When you come back to the site, the site says oh, your account requires a Security Key, prove you still have it. It sends one or more of those "random identifiers" corresponding to enrolled Security Keys. Your browser talks to any Security Keys plugged in, hey, I'm at SHA256("some.example") and it asked if anybody can prove I'm still some-huge-identifier ?

Your Security Key tries to decrypt some-huge-identifier using its symmetric key, and the Extra Data SHA256("some.example"). Maybe it gets a success and a private key. The little button flashes and you push it. In this case it can sign a message using the private key, "Yes, I'm still me, I checked a human was present"

But, if anything goes wrong, that decryption will fail. If this is some-other.example, SHA256("some-other.example") won't match and decryption fails. If the site picks random gibberish instead of your identifier, decryption fails. If you plugged in the wrong Security Key, decryption fails.

You are unable to even try to authenticate to the wrong site. And if they enroll you which they can do, now they've got useless credentials for you to sign into their site that are unrelated to the credentials on other sites. They're even deliberately not correlated and they aren't even wasting space on your Security Key, the Security Key (this is why the trick was so clever) doesn't store anything to make all this work! All the storage is in the Relying Parties, and it's all storage of public data that's harmless when inevitably crooks steal it.