Home / Ciberseguridad / A fake website walks off with your password; with a passkey there is nothing to take

A fake website walks off with your password; with a passkey there is nothing to take

The modern phishing kit no longer settles for cloning the login screen. Tools such as Evilginx or Tycoon 2FA stand up a reverse proxy between you and the real server: every keystroke, every six-digit code and every push notification are relayed live, and in the end the attacker walks away with the session cookie. In 2026 those kits have gone from elite threat-actor material to off-the-shelf product. The password, and the second factor that travels with it, does not fail because it is too short: it fails because it is a portable secret, and a portable secret gets handed over to anyone who asks for it with a convincing website.

The answer taking hold is not a longer password or another one-time code. It is a credential that cannot be told: the passkey, built on the FIDO2 and WebAuthn standards. The difference is not one of degree, it is one of nature.

A shared secret is a deliverable secret

When you create an account with a password, the server stores a derivative — usually a salted hash such as bcrypt or Argon2id — and you keep the original. Authenticating means proving that both sides know the same value. That design drags three structural holes along with it: the string can be guessed if it is weak, leaked if the database falls, and handed over if someone talks you into typing it into the wrong site.

The second factor plugs the first hole, not the third. A TOTP code is computed from a shared secret — a seed living both on your phone and on the server — and relaying it live is enough for whoever sits in the middle to clear the check. SMS is worse still: SIM swapping takes the code without ever touching your phone.

A passkey is a key pair tied to a domain

A passkey is an asymmetric key pair — one private, one public — generated inside an authenticator: the phone’s secure chip (Secure Enclave on iPhone, StrongBox or TEE on Android), the computer’s TPM, a USB hardware key or the password manager. The crucial point is that the private key never leaves it, not even to the browser that invokes it. The server only receives the public key, which is useless for impersonating anyone.

The usual algorithm is ES256, that is, ECDSA signatures over the P-256 curve; EdDSA (Ed25519) is also accepted and, in legacy deployments, RS256 with RSA. When the service needs to check who you are, it sends a random challenge and the authenticator answers with a signature. Signing is not handing over: the key cannot be deduced from the signature.

The second piece is the binding to the domain. WebAuthn handles two distinct identifiers. The first is the rpId, the service’s registrable domain (for instance, example.com), which travels hashed with SHA-256 in the first 32 bytes of the binary authData structure. The second is the full origin, with scheme, host and port (https://login.example.com), which the browser writes on its own into the clientDataJSON object. The authenticator signs the concatenation of authData with the SHA-256 of clientDataJSON: tamper with either one and the signature stops validating.

Registration: navigator.credentials.create()

When you register a passkey, the page calls the WebAuthn API and passes a random challenge (the value that makes recorded replay impossible), the list of accepted algorithms in pubKeyCredParams, the rpId and the authenticator preferences: whether any authenticator will do or only the one built into the device, whether the credential must be discoverable (resident, meaning usable without typing a username first) and how much attestation is requested.

The authenticator generates the key pair, keeps the private half and returns a credentialId together with the public key encoded in CBOR using the COSE format, plus the AAGUID, which identifies the authenticator model. The server verifies the ceremony type, the challenge, the origin, the signature and the rpId hash, then stores the credential and the public key. That is where registration ends: there is no password to store and no seed to replicate.

Login: a signature instead of a secret

During sign-in, the browser calls navigator.credentials.get() with a fresh challenge. In a username-first flow the site narrows the search with a list of credential identifiers (allowCredentials); in a usernameless flow it lets the authenticator pick among its resident credentials. The user confirms with fingerprint, face or PIN, which sets the user verification (UV) flag in the response and lets the site demand two factors in a single gesture.

The authenticator bumps its signature counter and returns an assertion. The server checks six things before granting the session: that the challenge matches, that the origin is on the allowed list, that the rpId hash maps to its own domain, that the signature validates against the stored public key, that the UV flag meets policy and that the counter has not gone backwards, which would signal a cloned credential.

Why phishing is left with nothing to steal

Picture a perfect replica of your bank at bank-examp1e.com. If the attacker asks for the real rpId, the browser refuses to proceed: bank.example.com is not a suffix of the domain running the code. If the attacker uses its own domain as rpId, the authenticator looks for credentials tied to that hash and finds none. There is no path to a valid signature, and there are two independent checkpoints — the browser fixing the origin and the authenticator enforcing the rpId — beyond the reach of the page’s JavaScript. A man-in-the-middle proxy does not help either: it can forward the real server’s challenge, but the browser will record the proxy’s origin and the server will reject it during verification.

What a passkey does not fix

The cryptography holds; what breaks is everything around the ceremony. Once you are authenticated, the server issues a session cookie, and that cookie is a bearer credential: whoever steals it — through XSS, a compromised endpoint or an unencrypted network — impersonates you without needing any passkey. Hence the push for mechanisms that pin the token to the device, such as DPoP, or for shorter sessions and re-authentication on sensitive actions.

Other side doors remain: OAuth consent phishing, where you authorise a malicious application from a legitimate screen; device-code phishing, which talks you into authorising the attacker’s session without stealing any credential; malware on the device; forged QR codes abusing the hybrid transport that jumps from phone to desktop; and, above all, account recovery flows, still the weakest link in any system advertised as phishing-resistant. An attacker who cannot break FIDO2 goes after new credential enrolment and the help desk.

Synced or device-bound

Not all passkeys behave the same. Synced passkeys live in the ecosystem keychain (iCloud Keychain, Google Password Manager, 1Password) and replicate across devices end-to-end encrypted; their advantage is recoverability: lose the phone and you keep access. Device-bound passkeys never leave a chip or a PIN-protected hardware key and offer the strongest guarantee, at the price of losing access when the key is lost. Attestation — proving which authenticator model was used — lets an organisation demand specific hardware, though verifying it carries an operational cost and privacy concerns, which is why Apple and Google ship anonymised attestations.

What is new in 2026: WebAuthn Level 3 and the PRF extension

On 20 July 2026 the W3C proposed advancing WebAuthn Level 3 to Recommendation, the last step of the standardisation process. Level 3 does not make passkeys more phishing-resistant — that was already settled in Level 2 — but it widens what a credential can do. The most consequential addition is the PRF extension: the authenticator evaluates a pseudo-random function over its internal secret and a salt sent by the service, and returns 32 bytes. Same salt, same rpId and same authenticator always yield the same value, which makes it possible to derive encryption keys without the private key ever leaving the chip. WhatsApp uses this mechanism to encrypt chat backups with a passkey instead of a password or a 64-digit key, and 1Password uses it to encrypt stored passkeys.

The other addition is Related Origin Requests (ROR): a domain can publish a /.well-known/webauthn file listing related origins that share its rpId, with a practical limit of five registrable domains. The browser still records the real origin and the server still verifies it, so the guarantee does not degrade: it merely formalises what used to force one credential per domain. Chrome and Edge 128+ and Safari 18 already support it.

Rolling it out without leaving anyone behind

The real obstacle for passkeys is logistics. Conditional UI, which offers credentials in the autofill of the username field, avoids the screen jump that kills conversion. Hybrid transport — that QR code leaping from phone to desktop — solves adoption on shared machines, though it deserves watching because of forged QR codes. And on the server there are details that get forgotten often: reject a registration when the credentialId already exists, because identifiers are probabilistically unique but not guaranteed, and do not leave the password as an open door forever, because the attacker will always take the weakest path.

Corporate environments already ship policies that accept only this family of methods: Entra ID’s “phishing-resistant MFA” authentication strength, for instance, allows FIDO2, Windows Hello, passkeys or certificates, and nothing on that list can be relayed through a proxy. The key to adoption is not convincing users it is safer, but making it more convenient than typing a password.

The uncomfortable conclusion

Passkeys do not win because they are longer or because nobody can remember them: they win because there is no transmissible secret left to steal. To date no practical attack has been published against the core cryptography of FIDO2/WebAuthn, which is why attackers’ effort has shifted to recovery flows, session cookies and fallback methods. Adding a passkey closes the front door; leaving the recovery window open does not.