Bei Passkeys vs. Passwörtern steht ein gemeinsames Geheimnis gegen Public-Key-Authentifizierung. Ein Passwort kennen der Nutzer und, in gehashter Form, der Server, und es funktioniert auf jeder Seite, die danach fragt, auch auf einer gefälschten. Ein Passkey ist ein WebAuthn-Credential: ein Schlüsselpaar, das für eine einzige Website erzeugt, auf dem Gerät des Nutzers per Fingerabdruck, Gesichtserkennung oder PIN entsperrt und zum Signieren einer frischen Challenge verwendet wird, die an die Identität der Website gebunden ist.
Auf einen Blick
| Passwort | Passkey | |
|---|---|---|
| Was der Nutzer beweist | Kenntnis eines gemeinsamen Geheimnisses | Besitz eines privaten Schlüssels, lokal per Biometrie oder PIN entsperrt |
| Was der Server speichert | Salt und langsamer Hash (Argon2id, scrypt, PBKDF2) | Credential-ID und öffentlicher Schlüssel (91 Byte für P-256 in der Demo unten) |
| Täuschend ähnliche Phishing-Website | Erhält das Passwort, wenn der Nutzer es eintippt | Erhält nichts Brauchbares: Das Credential ist an die RP-ID und den Origin der Website gebunden |
| Wiederverwendung auf mehreren Websites | Häufig, was Credential Stuffing ermöglicht | Unmöglich: ein Schlüsselpaar pro Website und Konto |
| Datenbank-Leak | Offline-Rateversuche gegen die Hashes | Nur öffentliche Schlüssel werden bekannt; nichts lässt sich erneut einspielen |
| NIST SP 800-63B-4 (Juli 2025) | Ein Faktor: mindestens 15 Zeichen, AAL1 | Kryptografisch mit mehreren Faktoren: AAL2; gerätegebundene Hardware-Schlüssel können AAL3 erreichen, synchronisierte Passkeys nicht |
| Verlorenes Gerät | Nicht betroffen | Synchronisierte Passkeys lassen sich über das Konto beim Anbieter wiederherstellen; gerätegebundene Schlüssel brauchen ein Backup-Credential |
| Andere Geräte | Überall eintippbar | Synchronisiert auf den Geräten des Anbieters; für andere Geräte QR-Code und Bluetooth-Näheprüfung (hybrid) |
| Standards | Keine über HTML-Formulare und HTTP-Authentifizierung hinaus | W3C WebAuthn Level 3 (Recommendation seit 25. August 2026), FIDO CTAP 2.2 |
Was bei der Anmeldung passiert
Bei der Registrierung erzeugt der Authenticator (ein Smartphone, Laptop, Passwortmanager oder Sicherheitsschlüssel) ein Schlüsselpaar für die Relying-Party-ID der Website, zum Beispiel example.com, und die Website speichert den öffentlichen Schlüssel. Bei der Anmeldung schickt die Website eine zufällige Challenge; der Browser fügt den Origin der Seite in die signierten Client-Daten ein, und der Authenticator signiert diese nach der Benutzerverifizierung zusammen mit einem Hash der RP-ID. Der Server prüft die Challenge, den Origin, den Hash der RP-ID und die Signatur.
Das folgende Skript (Node.js 26.10, Apple M4 Max) zeigt, was jeder Ansatz auf dem Server hinterlässt und welche Prüfungen eine täuschend ähnliche Website aufhalten.
import { argon2Sync, createHash, generateKeyPairSync, randomBytes, sign, verify } from "node:crypto";
const sha256 = (b) => createHash("sha256").update(b).digest();
// What a password database stores: an Argon2id hash (OWASP minimum: 19 MiB, t=2, p=1)
const params = { nonce: randomBytes(16), memory: 19456, passes: 2, parallelism: 1, tagLength: 32 };
const t0 = performance.now();
const tag = argon2Sync("argon2id", { message: "correct horse battery staple", ...params });
const ms = performance.now() - t0;
console.log(`password: stores salt + ${tag.length}-byte Argon2id hash; one guess costs ${ms.toFixed(0)} ms`);
// What a passkey database stores: the credential's public key
const { privateKey, publicKey } = generateKeyPairSync("ec", { namedCurve: "P-256" });
const spki = publicKey.export({ type: "spki", format: "der" });
console.log(`passkey: stores a ${spki.length}-byte public key; a leak lets nobody sign in`);
// Authenticator: signs authenticatorData || SHA-256(clientDataJSON)
function getAssertion(rpId, origin, challenge) {
const clientDataJSON = Buffer.from(JSON.stringify({ type: "webauthn.get", challenge, origin }));
const authData = Buffer.concat([sha256(rpId), Buffer.from([0x05]), Buffer.alloc(4)]);
const signature = sign("sha256", Buffer.concat([authData, sha256(clientDataJSON)]), privateKey);
return { clientDataJSON, authData, signature };
}
// Relying party: the checks from WebAuthn §7.2
function check(a, challenge) {
const c = JSON.parse(a.clientDataJSON);
return {
challenge: c.challenge === challenge,
origin: c.origin === "https://example.com",
rpIdHash: a.authData.subarray(0, 32).equals(sha256("example.com")),
signature: verify("sha256", Buffer.concat([a.authData, sha256(a.clientDataJSON)]), publicKey, a.signature),
};
}
const challenge = randomBytes(32).toString("base64url");
console.log("real site:", check(getAssertion("example.com", "https://example.com", challenge), challenge));
console.log("look-alike:", check(getAssertion("examp1e.com", "https://examp1e.com", challenge), challenge));
password: stores salt + 32-byte Argon2id hash; one guess costs 25 ms
passkey: stores a 91-byte public key; a leak lets nobody sign in
real site: { challenge: true, origin: true, rpIdHash: true, signature: true }
look-alike: { challenge: true, origin: false, rpIdHash: false, signature: true }
Der Fall der nachgeahmten Website ist bewusst großzügig zugunsten des Angreifers angelegt: In der Praxis weigert sich der Browser grundsätzlich, Credentials für example.com auf einer anderen Website zu verwenden, es entsteht also gar keine Signatur. Selbst eine Signatur, die ein Angreifer durch Weiterleiten der Sitzung erlangt, enthielte den falschen Origin und den falschen Hash der RP-ID. Deshalb stuft NIST WebAuthn dank der Bindung an den Namen des Verifizierers (Verifier Name Binding) als phishing-resistent ein, Passwörter, Einmalcodes und Push-Bestätigungen dagegen nicht. Argon2id lässt jeden Rateversuch für ein Passwort Dutzende Millisekunden kosten, doch Nutzer mit gängigen oder wiederverwendeten Passwörtern werden trotzdem schnell gefunden; ein öffentlicher Schlüssel bietet einem Angreifer nichts zum Raten.
Wo beide trotzdem scheitern
Passwörter scheitern an Wiederverwendung (Credential Stuffing mit geleakten Listen), an Phishing-Seiten und Phishing-Proxys in Echtzeit, die auch Einmalcodes abfangen, sowie an schwach gewählten Passwörtern. NIST SP 800-63B-4 verlangt deshalb mindestens 15 Zeichen für Passwörter als einzigen Faktor (8 innerhalb einer Multi-Faktor-Authentifizierung), verbietet Regeln zur Zusammensetzung und regelmäßige Wechsel, schreibt den Abgleich neuer Passwörter mit geleakten und gängigen Werten vor und empfiehlt, mindestens 64 Zeichen zuzulassen. Ein Passwortmanager mit Autofill, das nach Domain abgleicht, löst das Problem der Wiederverwendung und einen Teil des Phishings, aber nicht jeder Nutzer hat einen.
Passkeys verlagern das Risiko an zwei Stellen. Die erste ist das Konto beim Anbieter: Synchronisierte Passkeys sind nur so sicher wie das Konto bei Apple, Google, Microsoft oder dem Passwortmanager, in dem sie liegen; deshalb lässt NIST synchronisierte, exportierbare Schlüssel für AAL3 nicht zu. Die zweite ist die Kontowiederherstellung auf deiner Website: Lässt sich ein verlorener Passkey über einen E-Mail-Link oder einen SMS-Code ersetzen, nehmen Angreifer stattdessen diesen Weg. Außerdem brauchen Nutzer ein zweites Credential oder einen synchronisierenden Anbieter, damit sie sich nicht aussperren.
Wann welches Verfahren passt
- Websites und Apps für Endkunden: Passkeys als primäre Methode, erstellt direkt nach der nächsten Anmeldung mit Passwort; Passwörter optional.
- Anmeldung von Beschäftigten: Passkeys über deinen Identity Provider; gerätegebundene Sicherheitsschlüssel für Administratoren und andere AAL3-Rollen.
- Besonders wertvolle Endkundenkonten (Banking, E-Mail, Cloud-Konsolen): Passkeys plus ein starker Wiederherstellungsprozess, idealerweise ein zweiter registrierter Passkey.
- Gemeinsam genutzte Geräte und Kiosk-Geräte: hybride Anmeldung über das Smartphone des Nutzers, statt Credentials auf dem gemeinsam genutzten Gerät zu speichern.
- Protokolle ohne WebAuthn (IMAP, ältere VPNs, SSH): App-spezifische Passwörter oder OAuth-Flows, die in einem Browser beginnen, in dem Passkeys funktionieren.
Hinweise zur Migration
- Ergänze Passkeys neben Passwörtern: Biete nach einer erfolgreichen Anmeldung mit Passwort an, einen Passkey zu erstellen, oder nutze die bedingte Erstellung aus WebAuthn Level 3, um automatisch einen anzulegen, wenn der Passwortmanager des Browsers das unterstützt.
- Nutze die Autofill-Oberfläche: Rufe auf der Anmeldeseite
navigator.credentials.getmitmediation: "conditional"auf, damit Passkeys in den Vorschlägen des Benutzernamenfelds erscheinen. - Speichere, was du brauchst: Credential-ID, öffentlichen Schlüssel, Signaturzähler, Transporte, die Backup-Flags und die AAGUID, die den Anbieter benennt; der AAGUID-Lookup ordnet sie einem Produkt zu.
- Sichere die Wiederherstellung ab, bevor du Passwörter entfernst: Verlange einen vorhandenen Passkey, einen zweiten registrierten Passkey oder eine Identitätsprüfung, nicht nur einen E-Mail-Link.
- Halte die Anbieter auf dem aktuellen Stand: Nutze die Signal-Methoden aus Level 3, wenn Nutzer Credentials löschen oder Namen ändern, und gib verwandte Origins an, wenn die Anmeldung über mehrere Domains hinweg läuft.
- Teste in der Passkey-Sandbox und untersuche echte Antworten mit dem WebAuthn-Inspektor, bevor du ausrollst.
Quellen
- W3C Web Authentication Level 3 (§7.1 Registrierung, §7.2 Authentifizierungszeremonie)
- NIST SP 800-63B-4, Authentifizierung und Verwaltung von Authenticators (§3.1.1.2 Passwörter, §3.2.5 Phishing-Resistenz, Anhang B synchronisierbare Authenticators)
- FIDO Alliance: Spezifikation des Client to Authenticator Protocol 2.2
- OWASP: Cheat Sheet zur Passwortspeicherung
- RFC 9106, Argon2