Passkey für Anmeldungen ohne Passwort erstellen

Passkeys machen Nutzerkonten sicherer, einfacher und nutzerfreundlicher.

Passkeys erhöhen die Sicherheit, vereinfachen die Anmeldung und ersetzen Passwörter. Im Gegensatz zu normalen Passwörtern, die sich Nutzer merken und manuell eingeben müssen, nutzen Passkeys die Displaysperrenmechanismen des Geräts wie biometrische Daten oder PINs und reduzieren das Phishing-Risiko und den Diebstahl von Anmeldedaten.

Passkeys werden mithilfe von Passkey-Anbietern wie dem Google Passwortmanager und dem iCloud-Schlüsselbund geräteübergreifend synchronisiert.

Es muss ein Passkey erstellt werden, bei dem der private Schlüssel zusammen mit den erforderlichen Metadaten sicher beim Passkey-Anbieter und der öffentliche Schlüssel zur Authentifizierung auf Ihrem Server gespeichert wird. Der private Schlüssel gibt nach der Nutzerbestätigung in der gültigen Domain eine Signatur aus, wodurch Passkeys phishingresistent sind. Der öffentliche Schlüssel verifiziert die Signatur, ohne vertrauliche Anmeldedaten zu speichern. Dadurch sind Passkeys resistent gegen den Diebstahl von Anmeldedaten.

So erstellen Sie einen Passkey

Bevor sich ein Nutzer mit einem Passkey anmelden kann, müssen Sie den Passkey erstellen, mit einem Nutzerkonto verknüpfen und seinen öffentlichen Schlüssel auf Ihrem Server speichern.

Sie können Nutzer in einer der folgenden Situationen bitten, einen Passkey zu erstellen:

  • Während oder nach der Registrierung
  • Nach der Anmeldung.
  • Nach der Anmeldung mit einem Passkey von einem anderen Gerät (d. h. [authenticatorAttachment](https://web.dev/articles/passkey-form-autofill#authenticator-attachment) ist cross-platform).
  • Auf einer speziellen Seite, auf der Nutzer ihre Passkeys verwalten können.

Zum Erstellen eines Passkeys verwenden Sie die WebAuthn API.

Die vier Komponenten des Registrierungsvorgangs für Passkeys sind:

  • Backend: Hier werden Details zum Nutzerkonto gespeichert, einschließlich des öffentlichen Schlüssels.
  • Frontend: Kommuniziert mit dem Browser und ruft die erforderlichen Daten aus dem Backend ab.
  • Browser: Führt JavaScript aus und interagiert mit der WebAuthn API.
  • Passkey-Anbieter: Erstellt und speichert den Passkey. Das ist in der Regel ein Passwortmanager wie der Google Passwortmanager oder ein Sicherheitsschlüssel.
Erstellen und Registrieren eines Passkeys
Das Erstellen und Registrieren eines Passkeys.

Bevor Sie einen Passkey erstellen, prüfen Sie, ob das System die folgenden Voraussetzungen erfüllt:

  • Das Nutzerkonto wird innerhalb eines möglichst kurzen Zeitraums mit einer sicheren Methode (z. B. per E-Mail, Telefonbestätigung oder Identitätsföderation) bestätigt.

  • Das Frontend und das Backend können sicher kommunizieren, um Anmeldedaten auszutauschen.

  • Der Browser unterstützt WebAuthn und das Erstellen von Passkeys.

In den folgenden Abschnitten zeigen wir Ihnen, wie Sie die meisten davon prüfen können.

Sobald das System diese Bedingungen erfüllt, wird ein Passkey erstellt:

  1. Das System löst die Erstellung eines Passkeys aus, wenn der Nutzer die Aktion ausführt, z. B. auf der Seite zur Passkey-Verwaltung auf die Schaltfläche „Passkey erstellen“ klickt oder die Registrierung abschließt.
  2. Das Frontend fordert die erforderlichen Anmeldedaten vom Backend an, einschließlich Nutzerinformationen, einer Herausforderung und Anmeldedaten-IDs, um Duplikate zu vermeiden.
  3. Das Frontend ruft navigator.credentials.create() auf, um den Passkey-Anbieter des Geräts aufzufordern, einen Passkey mit den Informationen aus dem Backend zu generieren. Hinweis: Dieser Aufruf gibt ein Versprechen zurück.
  4. Das Gerät des Nutzers authentifiziert ihn mithilfe einer biometrischen Methode, einer PIN oder eines Musters, um den Passkey zu erstellen.
  5. Der Passkey-Anbieter erstellt einen Passkey und gibt eine öffentliche Schlüssel-Anmeldedaten an die Frontend zurück, wodurch die Zusicherung erfüllt wird.
  6. Das Frontend sendet die generierten Public-Key-Anmeldedaten an das Backend.
  7. Das Backend speichert den öffentlichen Schlüssel und andere wichtige Daten für die zukünftige Authentifizierung.
  8. Das Backend benachrichtigt den Nutzer (z. B. per E-Mail), um die Erstellung des Passkeys zu bestätigen und potenziellen unbefugten Zugriff zu erkennen.

So wird ein sicherer und nahtloser Registrierungsprozess für Passkeys für Nutzer gewährleistet.

Kompatibilitäten

Die meisten Browser unterstützen WebAuthn, es gibt jedoch einige kleinere Lücken. Unter passkeys.dev finden Sie Details zur Browser- und Betriebssystemkompatibilität.

Neuen Passkey erstellen

So sollte das Frontend beim Erstellen eines neuen Passkeys vorgehen:

  1. Prüfen Sie die Kompatibilität.
  2. Informationen aus dem Backend abrufen
  3. WebAuth API aufrufen, um einen Passkey zu erstellen
  4. Senden Sie den zurückgegebenen öffentlichen Schlüssel an das Backend.
  5. Speichern Sie die Anmeldedaten.

In den folgenden Abschnitten wird beschrieben, wie Sie das tun können.

Auf Kompatibilität prüfen

Bevor die Schaltfläche „Neuen Passkey erstellen“ angezeigt wird, sollte das Front-End prüfen, ob folgende Bedingungen erfüllt sind:

  • Der Browser unterstützt WebAuthn mit PublicKeyCredential.

Browser Support

  • Chrome: 67.
  • Edge: 18.
  • Firefox: 60.
  • Safari: 13.

Source

  • Das Gerät unterstützt einen Plattform-Authentifikator (kann einen Passkey erstellen und sich damit authentifizieren) mit PublicKeyCredential.isUserVerifyingPlatformAuthenticatorAvailable().

Browser Support

  • Chrome: 67.
  • Edge: 18.
  • Firefox: 60.
  • Safari: 13.

Source

Browser Support

  • Chrome: 108.
  • Edge: 108.
  • Firefox: 119.
  • Safari: 16.

Source

Im folgenden Code-Snippet wird gezeigt, wie Sie die Kompatibilität prüfen können, bevor die Passkey-bezogenen Optionen angezeigt werden.

// Availability of `window.PublicKeyCredential` means WebAuthn is usable.  
// `isUserVerifyingPlatformAuthenticatorAvailable` means the feature detection is usable.  
// `isConditionalMediationAvailable` means the feature detection is usable.  
if (window.PublicKeyCredential &&  
    PublicKeyCredential.isUserVerifyingPlatformAuthenticatorAvailable &&  
    PublicKeyCredential.isConditionalMediationAvailable) {  
  // Check if user verifying platform authenticator is available.  
  Promise.all([  
    PublicKeyCredential.isUserVerifyingPlatformAuthenticatorAvailable(),  
    PublicKeyCredential.isConditionalMediationAvailable(),  
  ]).then(results => {  
    if (results.every(r => r === true)) {  
      // Display "Create a new passkey" button  
    }  
  });  
}  

In diesem Beispiel sollte die Schaltfläche Neuen Passkey erstellen nur angezeigt werden, wenn alle Bedingungen erfüllt sind.

Informationen aus dem Backend abrufen

Wenn der Nutzer auf die Schaltfläche klickt, werden die erforderlichen Informationen aus dem Backend abgerufen, um navigator.credentials.create() aufzurufen.

Das folgende Code-Snippet zeigt ein JSON-Objekt mit den erforderlichen Informationen zum Aufrufen von navigator.credentials.create():

// Example `PublicKeyCredentialCreationOptions` contents
{
  challenge: *****,
  rp: {
    name: "Example",
    id: "example.com",
  },
  user: {
    id: *****,
    name: "john78",
    displayName: "John",
  },
  pubKeyCredParams: [{
    alg: -7, type: "public-key"
  },{
    alg: -257, type: "public-key"
  }],
  excludeCredentials: [{
    id: *****,
    type: 'public-key',
    transports: ['internal'],
  }],
  authenticatorSelection: {
    authenticatorAttachment: "platform",
    requireResidentKey: true,
  }
}

Die Schlüssel/Wert-Paare im Objekt enthalten die folgenden Informationen:

  • challenge: Eine servergenerierte Herausforderung in ArrayBuffer für diese Registrierung.
  • rp.id: Für eine RP-ID (Relying Party ID), eine Domain und eine Website kann entweder die Domain oder ein registrierbares Suffix angegeben werden. Wenn der Ursprung eines RP beispielsweise https://login.example.com:1337 ist, kann die RP-ID entweder login.example.com oder example.com sein. Wenn die RP-ID als example.com angegeben ist, kann sich der Nutzer bei login.example.com oder bei allen Subdomains von example.com authentifizieren. Weitere Informationen finden Sie unter Passkeys für alle Websites mit ähnlichen Ursprungsanfragen wiederverwenden.
  • rp.name: Der Name der vertrauenden Seite. Diese Option ist in WebAuthn L3 veraltet, wird aber aus Kompatibilitätsgründen berücksichtigt.
  • user.id: Eine eindeutige Nutzer-ID in ArrayBuffer, die beim Erstellen des Kontos generiert wird. Er sollte dauerhaft sein, im Gegensatz zu einem Nutzernamen, der bearbeitet werden kann. Die User-ID identifiziert ein Konto, darf aber keine personenidentifizierbaren Informationen enthalten. Sie haben wahrscheinlich bereits eine Nutzer-ID in Ihrem System. Falls nicht, erstellen Sie eine speziell für Passkeys, damit sie keine personenidentifizierbaren Informationen enthält.
  • user.name: Eine eindeutige Kennung für das Konto, die der Nutzer erkennt, z. B. seine E-Mail-Adresse oder sein Nutzername. Dieser wird in der Kontoauswahl angezeigt.
  • user.displayName: Ein erforderlicher, nutzerfreundlicherer Name für das Konto. Er muss nicht eindeutig sein und kann der vom Nutzer ausgewählte Name sein. Wenn für Ihre Website kein geeigneter Wert vorhanden ist, geben Sie einen leeren String an. Je nach Browser wird diese Option möglicherweise in der Kontoauswahl angezeigt.
  • pubKeyCredParams: Gibt die von der RP (relying party) unterstützten Public-Key-Algorithmen an. Wir empfehlen, [{alg: -7, type: "public-key"},{alg: -257, type: "public-key"}] festzulegen. Damit wird die Unterstützung von ECDSA mit P-256 und RSA PKCS#1 angegeben. Die Unterstützung dieser beiden Verfahren bietet eine vollständige Abdeckung.
  • excludeCredentials: Eine Liste der bereits registrierten Anmeldedaten-IDs. Verhindert die doppelte Registrierung desselben Geräts, indem eine Liste der bereits registrierten Anmeldedaten-IDs angegeben wird. Das Mitglied transports sollte, falls angegeben, das Ergebnis des Aufrufs von getTransports() während der Registrierung der einzelnen Anmeldedaten enthalten.
  • authenticatorSelection.authenticatorAttachment: Legen Sie diese Option zusammen mit hint: ['client-device'] auf "platform" fest, wenn die Erstellung dieses Passkeys ein Upgrade von einem Passwort ist, z. B. in einer Werbeaktion nach einer Anmeldung. "platform" gibt an, dass der RP einen Plattform-Authenticator (einen in das Plattformgerät eingebetteten Authenticator) benötigt, der beispielsweise nicht zum Einsetzen eines USB-Sicherheitsschlüssels auffordert. Der Nutzer hat eine einfachere Möglichkeit, einen Passkey zu erstellen.
  • authenticatorSelection.requireResidentKey: Legen Sie einen booleschen true fest. In einem auffindbaren Anmeldedatensatz (Resident Key) werden Nutzerinformationen im Passkey gespeichert und Nutzer können bei der Authentifizierung das Konto auswählen.
  • authenticatorSelection.userVerification: Gibt an, ob eine Nutzerbestätigung über die Displaysperre des Geräts "required", "preferred" oder "discouraged" ist. Der Standardwert ist "preferred". Das bedeutet, dass der Authenticator die Nutzerbestätigung möglicherweise überspringt. Legen Sie dafür "preferred" fest oder lassen Sie das Attribut weg.

Wir empfehlen, das Objekt auf dem Server zu erstellen, das ArrayBuffer mit Base64URL zu codieren und es aus dem Frontend abzurufen. So kannst du die Nutzlast mit PublicKeyCredential.parseCreationOptionsFromJSON() decodieren und direkt an navigator.credentials.create() übergeben.

Im folgenden Code-Snippet wird gezeigt, wie Sie die Informationen abrufen und decodieren, die zum Erstellen des Passkeys erforderlich sind.

// Fetch an encoded `PubicKeyCredentialCreationOptions` from the server.
const _options = await fetch('/webauthn/registerRequest');

// Deserialize and decode the `PublicKeyCredentialCreationOptions`.
const decoded_options = JSON.parse(_options);
const options = PublicKeyCredential.parseCreationOptionsFromJSON(decoded_options);
...

WebAuthn API aufrufen, um einen Passkey zu erstellen

Rufen Sie navigator.credentials.create() auf, um einen neuen Passkey zu erstellen. Die API gibt ein Versprechen zurück und wartet auf die Interaktion des Nutzers, der ein modales Dialogfeld aufruft.

Browser Support

  • Chrome: 60.
  • Edge: 18.
  • Firefox: 60.
  • Safari: 13.

Source

// Invoke WebAuthn to create a passkey.
const credential = await navigator.credentials.create({
  publicKey: options
});

Die zurückgegebenen Public-Key-Anmeldedaten an das Backend senden

Nachdem der Nutzer über die Bildschirmsperre des Geräts bestätigt wurde, wird ein Passkey erstellt und das Versprechen wird erfüllt, indem ein PublicKeyCredential-Objekt an das Frontend zurückgegeben wird.

Das Versprechen kann aus verschiedenen Gründen abgelehnt werden. Sie können diese Fehler beheben, indem Sie die Eigenschaft name des Error-Objekts prüfen:

  • InvalidStateError: Auf dem Gerät ist bereits ein Passkey vorhanden. Dem Nutzer wird kein Fehlerdialogfeld angezeigt. Die Website sollte dies nicht als Fehler behandeln. Der Nutzer wollte, dass das lokale Gerät registriert wird, und das ist der Fall.
  • NotAllowedError: Der Nutzer hat den Vorgang abgebrochen.
  • AbortError: Der Vorgang wurde abgebrochen.
  • Andere Ausnahmen: Ein unerwarteter Fehler ist aufgetreten. Der Browser zeigt dem Nutzer ein Fehlerdialogfeld an.

Das Objekt „Public-Key-Anmeldedaten“ enthält die folgenden Eigenschaften:

  • id: Eine Base64URL-codierte ID des erstellten Passkeys. Anhand dieser ID kann der Browser bei der Authentifizierung feststellen, ob sich auf dem Gerät ein passender Passkey befindet. Dieser Wert muss in der Datenbank im Backend gespeichert werden.
  • rawId: Eine ArrayBuffer-Version der Anmeldedaten-ID.
  • response.clientDataJSON: Mit ArrayBuffer codierte Clientdaten.
  • response.attestationObject: Ein mit ArrayBuffer codiertes Attestierungsobjekt. Diese enthält wichtige Informationen wie eine RP-ID, Flags und einen öffentlichen Schlüssel.
  • authenticatorAttachment: Wird "platform" zurückgegeben, wenn diese Anmeldedaten auf einem Gerät mit Passkey erstellt wurden.
  • type: Dieses Feld ist immer auf "public-key" gesetzt.

Codieren Sie das Objekt mit der Methode .toJSON(), serialisieren Sie es mit JSON.stringify() und senden Sie es an den Server.

...

// Encode and serialize the `PublicKeyCredential`.
const _result = credential.toJSON();
const result = JSON.stringify(_result);

// Encode and send the credential to the server for verification.  
const response = await fetch('/webauthn/registerResponse', {
  method: 'post',
  credentials: 'same-origin',
  body: result
});
...

Anmeldedaten speichern

Nachdem du die öffentlichen Anmeldedaten im Backend erhalten hast, empfehlen wir, eine serverseitige Bibliothek oder eine Lösung zu verwenden, anstatt eigenen Code zur Verarbeitung öffentlicher Anmeldedaten zu schreiben.

Sie können die aus den Anmeldedaten abgerufenen Informationen dann für die zukünftige Verwendung in der Datenbank speichern.

In der folgenden Liste finden Sie empfohlene Properties, die Sie speichern sollten:

  • Anmeldedaten-ID: Die Anmeldedaten-ID, die mit den Public-Key-Anmeldedaten zurückgegeben wird.
  • Name der Anmeldedaten: Der Name der Anmeldedaten. Benennen Sie ihn nach dem Passkey-Anbieter, über den er erstellt wurde, der anhand der AAGUID identifiziert werden kann.
  • Nutzer-ID: Die Nutzer-ID, mit der der Passkey erstellt wurde.
  • öffentlicher Schlüssel: Der öffentliche Schlüssel, der mit den Public-Key-Anmeldedaten zurückgegeben wird. Dies ist erforderlich, um eine Passkey-Bestätigung zu überprüfen.
  • Datum und Uhrzeit der Erstellung: Datum und Uhrzeit der Erstellung des Passkeys. Das ist nützlich, um den Passkey zu identifizieren.
  • Datum und Uhrzeit der letzten Verwendung: Hier wird das Datum und die Uhrzeit der letzten Anmeldung des Nutzers mit dem Passkey aufgezeichnet. So können Sie feststellen, welchen Passkey der Nutzer verwendet hat (oder nicht).
  • AAGUID: Eine eindeutige Kennung des Passkey-Anbieters.
  • Flag für die Back-up-Berechtigung: „true“, wenn das Gerät für die Passkey-Synchronisierung infrage kommt. Anhand dieser Informationen können Nutzer auf der Seite zur Passkey-Verwaltung synchronisierbare Passkeys und gerätegebundene (nicht synchronisierbare) Passkeys unterscheiden.

Eine ausführlichere Anleitung finden Sie unter Serverseitige Passkey-Registrierung.

Signal bei fehlgeschlagener Registrierung

Wenn die Registrierung eines Passkeys fehlschlägt, kann das für den Nutzer verwirrend sein. Wenn sich ein Passkey beim Passkey-Anbieter befindet und für den Nutzer verfügbar ist, der zugehörige öffentliche Schlüssel aber nicht auf der Serverseite gespeichert ist, können Anmeldeversuche mit dem Passkey nie erfolgreich sein und die Fehlerbehebung ist schwierig. Informiere den Nutzer in diesem Fall darüber.

Um dies zu verhindern, können Sie mithilfe der Signal API einen unbekannten Passkey an den Passkey-Anbieter senden. Durch Aufrufen von PublicKeyCredential.signalUnknownCredential() mit einer RP-ID und einer Anmeldedaten-ID kann der RP den Passkey-Anbieter darüber informieren, dass die angegebenen Anmeldedaten entfernt wurden oder nicht vorhanden sind. Es liegt im Ermessen des Passkey-Anbieters, wie er mit diesem Signal umgeht. Wenn es unterstützt wird, wird der zugehörige Passkey voraussichtlich entfernt.

// Detect authentication failure due to lack of the credential
if (response.status === 404) {
  // Feature detection
  if (PublicKeyCredential.signalUnknownCredential) {
    await PublicKeyCredential.signalUnknownCredential({
      rpId: "example.com",
      credentialId: "vI0qOggiE3OT01ZRWBYz5l4MEgU0c7PmAA" // base64url encoded credential ID
    });
  } else {
    // Encourage the user to delete the passkey from the password manager nevertheless.
    ...
  }
}

Weitere Informationen zur Signal API finden Sie unter Passkeys mit Anmeldedaten auf Ihrem Server mit der Signal API abgleichen.

Benachrichtigung an den Nutzer senden

Wenn beim Registrieren eines Passkeys eine Benachrichtigung (z. B. eine E-Mail) gesendet wird, können Nutzer unbefugte Kontozugriffe erkennen. Wenn ein Angreifer einen Passkey ohne Wissen des Nutzers erstellt, kann dieser Passkey auch nach der Passwortänderung für zukünftige Missbrauchsversuche verwendet werden. Die Benachrichtigung warnt den Nutzer und hilft, dies zu verhindern.

Checkliste

  • Bestätigen Sie den Nutzer (vorzugsweise per E-Mail oder mit einer sicheren Methode), bevor Sie ihm erlauben, einen Passkey zu erstellen.
  • Mit excludeCredentials können Sie verhindern, dass doppelte Passkeys für denselben Passkey-Anbieter erstellt werden.
  • Speichern Sie die AAGUID, um den Passkey-Anbieter zu identifizieren und die Anmeldedaten für den Nutzer zu benennen.
  • Signalisieren, wenn ein Versuch, einen Passkey zu registrieren, mit PublicKeyCredential.signalUnknownCredential() fehlschlägt.
  • Senden Sie dem Nutzer eine Benachrichtigung, nachdem er einen Passkey für sein Konto erstellt und registriert hat.

Ressourcen

Nächster Schritt: Über das Autofill-Formular mit einem Passkey anmelden