Übersicht
Hier ist eine grobe Übersicht über die wichtigsten Schritte bei der Registrierung eines Passkeys:
- Legen Sie Optionen zum Erstellen eines Passkeys fest. Senden Sie sie an den Client, damit Sie sie an Ihren Aufruf zur Passkey-Erstellung weitergeben können: den WebAuthn API-Aufruf
navigator.credentials.create
im Web undcredentialManager.createCredential
unter Android. Nachdem der Nutzer die Erstellung des Passkeys bestätigt hat, wird der Anruf zum Erstellen des Passkeys aufgelöst und es werden AnmeldedatenPublicKeyCredential
zurückgegeben. - Überprüfen Sie die Anmeldedaten und speichern Sie sie auf dem Server.
In den folgenden Abschnitten werden die einzelnen Schritte ausführlich erläutert.
<ph type="x-smartling-placeholder">Optionen zum Erstellen von Anmeldedaten erstellen
Der erste Schritt, den Sie auf dem Server ausführen müssen, besteht darin, ein PublicKeyCredentialCreationOptions
-Objekt zu erstellen.
Nutzen Sie dazu Ihre serverseitige FIDO-Bibliothek. Normalerweise wird eine Dienstfunktion zur Verfügung gestellt, die diese Optionen für Sie erstellen kann. SimpleWebAuthn bietet zum Beispiel generateRegistrationOptions
.
PublicKeyCredentialCreationOptions
sollte alles enthalten, was für das Erstellen eines Passkeys erforderlich ist: Informationen über den Nutzer, über die RP und eine Konfiguration für die Attribute der erstellten Anmeldedaten. Nachdem Sie alle diese Elemente definiert haben, übergeben Sie sie nach Bedarf an die Funktion in Ihrer serverseitigen FIDO-Bibliothek, die für die Erstellung des PublicKeyCredentialCreationOptions
-Objekts zuständig ist.
Einige von PublicKeyCredentialCreationOptions
Felder können Konstanten sein. Andere sollten dynamisch auf dem Server definiert werden:
rpId
: Um die RP-ID auf dem Server auszufüllen, verwenden Sie serverseitige Funktionen oder Variablen, mit denen Sie den Hostnamen Ihrer Webanwendung ermitteln, z. B.example.com
.user.name
unduser.displayName
:Verwenden Sie zum Ausfüllen dieser Felder die Sitzungsinformationen des angemeldeten Nutzers oder die Informationen des neuen Nutzerkontos, falls der Nutzer bei der Registrierung einen Passkey erstellt.user.name
ist in der Regel eine E-Mail-Adresse und eindeutig für die RP.user.displayName
ist ein nutzerfreundlicher Name. Nicht alle Plattformen verwendendisplayName
.user.id
: Ein zufälliger, eindeutiger String, der bei der Kontoerstellung generiert wird. Im Gegensatz zu Nutzernamen, die bearbeitet werden können, sollte sie dauerhaft sein. Mit der User-ID wird ein Konto identifiziert, sie darf aber keine personenidentifizierbaren Informationen enthalten. Sie haben wahrscheinlich bereits eine Nutzer-ID in Ihrem System, aber bei Bedarf erstellen Sie eine speziell für Passkeys, damit sie keine personenidentifizierbaren Informationen enthält.excludeCredentials
: Eine Liste der vorhandenen Anmeldedaten IDs, um das Duplizieren eines Passkeys vom Passkey-Anbieter zu verhindern. Suchen Sie in Ihrer Datenbank nach den für diesen Nutzer vorhandenen Anmeldedaten, um dieses Feld auszufüllen. Weitere Informationen finden Sie im Hilfeartikel Erstellen eines neuen Passkeys verhindern, wenn bereits ein Passkey vorhanden ist.challenge
: Für die Registrierung von Anmeldedaten ist die Identitätsbestätigung nur relevant, wenn Sie eine Attestierung verwenden. Das ist eine fortgeschrittenere Methode, um die Identität eines Passkey-Anbieters und die ausgegebenen Daten zu überprüfen. Aber auch wenn Sie die Attestierung nicht verwenden, ist die Identitätsbestätigung ein Pflichtfeld. In diesem Fall können Sie diese Aufgabe der Einfachheit halber auf ein einzelnes0
festlegen. Eine Anleitung dazu, wie Sie eine sichere Identitätsbestätigung für die Authentifizierung erstellen, finden Sie im Hilfeartikel Serverseitige Passkey-Authentifizierung.
Codierung und Decodierung
<ph type="x-smartling-placeholder">![PublicKeyCredentialCreationOptions vom Server gesendet](https://developers-dot-devsite-v2-prod.appspot.com/identity/passkeys/developer-guides/server-registration/images/server-publicKeyCredentialCreationOptions.png?authuser=5&hl=de)
PublicKeyCredentialCreationOptions
vom Server gesendet. challenge
, user.id
und excludeCredentials.credentials
müssen serverseitig in base64URL
codiert werden, damit PublicKeyCredentialCreationOptions
über HTTPS übertragen werden kann.PublicKeyCredentialCreationOptions
enthält ArrayBuffer
-Felder, die von JSON.stringify()
nicht unterstützt werden. Das bedeutet, dass einige Felder derzeit auf dem Server mit base64URL
manuell codiert und dann auf dem Client decodiert werden müssen, um PublicKeyCredentialCreationOptions
über HTTPS zu senden.
- Auf dem Server wird die Codierung und Decodierung in der Regel von Ihrer serverseitigen FIDO-Bibliothek übernommen.
- Auf dem Client muss die Codierung und Decodierung derzeit manuell erfolgen. In Zukunft wird dies einfacher: Es wird eine Methode zur Konvertierung von Optionen als JSON in
PublicKeyCredentialCreationOptions
verfügbar sein. Überprüfen Sie den Status der Implementierung in Chrome.
Beispielcode: Optionen zum Erstellen von Anmeldedaten erstellen
Wir verwenden in unseren Beispielen die SimpleWebAuthn-Bibliothek. Hier übergeben wir die Erstellung von Optionen für öffentliche Schlüssel-Anmeldedaten an die entsprechende generateRegistrationOptions
-Funktion.
import {
generateRegistrationOptions,
verifyRegistrationResponse,
generateAuthenticationOptions,
verifyAuthenticationResponse
} from '@simplewebauthn/server';
import { isoBase64URL } from '@simplewebauthn/server/helpers';
router.post('/registerRequest', csrfCheck, sessionCheck, async (req, res) => {
const { user } = res.locals;
// Ensure you nest verification function calls in try/catch blocks.
// If something fails, throw an error with a descriptive error message.
// Return that message with an appropriate error code to the client.
try {
// `excludeCredentials` prevents users from re-registering existing
// credentials for a given passkey provider
const excludeCredentials = [];
const credentials = Credentials.findByUserId(user.id);
if (credentials.length > 0) {
for (const cred of credentials) {
excludeCredentials.push({
id: isoBase64URL.toBuffer(cred.id),
type: 'public-key',
transports: cred.transports,
});
}
}
// Generate registration options for WebAuthn create
const options = generateRegistrationOptions({
rpName: process.env.RP_NAME,
rpID: process.env.HOSTNAME,
userID: user.id,
userName: user.username,
userDisplayName: user.displayName || '',
attestationType: 'none',
excludeCredentials,
authenticatorSelection: {
authenticatorAttachment: 'platform',
requireResidentKey: true
},
});
// Keep the challenge in the session
req.session.challenge = options.challenge;
return res.json(options);
} catch (e) {
console.error(e);
return res.status(400).send({ error: e.message });
}
});
Öffentlichen Schlüssel speichern
<ph type="x-smartling-placeholder">![PublicKeyCredentialCreationOptions vom Server gesendet](https://developers-dot-devsite-v2-prod.appspot.com/identity/passkeys/developer-guides/server-registration/images/server-publicKeyCredentialCreationOptions.png?authuser=5&hl=de)
navigator.credentials.create
gibt ein PublicKeyCredential
-Objekt zurück.Wenn navigator.credentials.create
auf dem Client aufgelöst wird, bedeutet dies, dass ein Passkey erstellt wurde. Ein PublicKeyCredential
-Objekt wird zurückgegeben.
Das PublicKeyCredential
-Objekt enthält ein AuthenticatorAttestationResponse
-Objekt, das die Antwort des Passkey-Anbieters auf die Anweisung des Clients zum Erstellen eines Passkeys darstellt. Es enthält Informationen zu den neuen Anmeldedaten, die Sie als RP benötigen, um den Nutzer später zu authentifizieren. Weitere Informationen zu AuthenticatorAttestationResponse
finden Sie in Anhang: AuthenticatorAttestationResponse
.
Senden Sie das Objekt PublicKeyCredential
an den Server. Bestätigen Sie die E-Mail, nachdem Sie sie erhalten haben.
Übergeben Sie diesen Bestätigungsschritt an Ihre serverseitige FIDO-Bibliothek. Für diesen Zweck wird in der Regel eine Dienstfunktion bereitgestellt. SimpleWebAuthn bietet zum Beispiel verifyRegistrationResponse
. Weitere Informationen dazu finden Sie im Anhang: Überprüfung der Registrierungsantwort.
Nach erfolgreicher Bestätigung sollten Sie Anmeldedaten in Ihrer Datenbank speichern, damit sich der Nutzer später mit dem Passkey authentifizieren kann, der mit diesen Anmeldedaten verknüpft ist.
Verwenden Sie eine dedizierte Tabelle für öffentliche Schlüssel-Anmeldedaten, die mit Passkeys verknüpft sind. Ein Nutzer kann nur ein Passwort, aber mehrere Passkeys haben, z. B. einen Passkey, der über den Apple iCloud-Schlüsselbund und einen über den Google Passwortmanager synchronisiert wird.
Hier ist ein Beispielschema, das Sie zum Speichern von Anmeldedaten verwenden können:
- Tabelle Nutzer:
<ph type="x-smartling-placeholder">
- </ph>
user_id
: Die primäre Nutzer-ID. Eine zufällige, eindeutige, permanente ID für den Nutzer. Verwenden Sie diesen Schlüssel als Primärschlüssel für Ihre Tabelle Nutzer.username
Ein benutzerdefinierter Nutzername, der möglicherweise bearbeitet werden kann.passkey_user_id
: Die Nutzer-ID ohne Passkey, die in Ihren Registrierungsoptionen durchuser.id
dargestellt wird. Wenn der Nutzer später versucht, sich zu authentifizieren, stellt der Authenticator diesepasskey_user_id
in seiner Authentifizierungsantwort inuserHandle
zur Verfügung. Wir empfehlen,passkey_user_id
nicht als Primärschlüssel festzulegen. Primärschlüssel werden in Systemen in der Regel zu personenidentifizierbaren Informationen, da sie intensiv genutzt werden.
- Tabelle mit Anmeldedaten für öffentlichen Schlüssel:
<ph type="x-smartling-placeholder">
- </ph>
id
: Anmeldedaten-ID. Verwenden Sie diesen Schlüssel als Primärschlüssel für Ihre Tabelle mit den Anmeldedaten für öffentlichen Schlüssel.public_key
: Der öffentliche Schlüssel des Berechtigungsnachweises.passkey_user_id
: Verwenden Sie dies als Fremdschlüssel, um eine Verknüpfung mit der Tabelle Nutzer herzustellen.backed_up
: Ein Passkey wird gesichert, wenn er vom Passkey-Anbieter synchronisiert wird. Das Speichern des Sicherungsstatus ist nützlich, wenn Sie Passwörter für Nutzer mitbacked_up
Passkeys in Zukunft löschen möchten. Sie können prüfen, ob der Passkey gesichert ist, indem Sie die Markierungen inauthenticatorData
prüfen oder eine serverseitige FIDO-Bibliotheksfunktion verwenden, die normalerweise verfügbar ist, um einfachen Zugriff auf diese Informationen zu ermöglichen. Die Speicherung der Informationen zur Sicherung kann hilfreich sein, um potenzielle Nutzeranfragen zu bearbeiten.name
: Optional ein Anzeigename für die Anmeldedaten, damit Nutzer den Anmeldedaten benutzerdefinierte Namen geben könnentransports
: ein Array von transports. Das Speichern von Transporten ist für die Authentifizierung des Nutzers hilfreich. Wenn Übertragungen verfügbar sind, kann sich der Browser entsprechend verhalten und eine UI anzeigen, die dem Transport entspricht, den der Passkey-Anbieter für die Kommunikation mit Clients verwendet – insbesondere für Anwendungsfälle mit einer erneuten Authentifizierung, in denenallowCredentials
nicht leer ist.
Andere Informationen können für die Nutzer hilfreich sein, z. B. der Passkey-Anbieter, der Erstellungszeitpunkt der Anmeldedaten und die letzte Nutzung. Weitere Informationen finden Sie unter Passkeys-Benutzeroberfläche.
Beispielcode: Anmeldedaten speichern
Wir verwenden in unseren Beispielen die SimpleWebAuthn-Bibliothek.
Hier übergeben wir die Bestätigung der Registrierungsantwort an die Funktion verifyRegistrationResponse
.
import { isoBase64URL } from '@simplewebauthn/server/helpers';
router.post('/registerResponse', csrfCheck, sessionCheck, async (req, res) => {
const expectedChallenge = req.session.challenge;
const expectedOrigin = getOrigin(req.get('User-Agent'));
const expectedRPID = process.env.HOSTNAME;
const response = req.body;
// This sample code is for registering a passkey for an existing,
// signed-in user
// Ensure you nest verification function calls in try/catch blocks.
// If something fails, throw an error with a descriptive error message.
// Return that message with an appropriate error code to the client.
try {
// Verify the credential
const { verified, registrationInfo } = await verifyRegistrationResponse({
response,
expectedChallenge,
expectedOrigin,
expectedRPID,
requireUserVerification: false,
});
if (!verified) {
throw new Error('Verification failed.');
}
const { credentialPublicKey, credentialID } = registrationInfo;
// Existing, signed-in user
const { user } = res.locals;
// Save the credential
await Credentials.update({
id: base64CredentialID,
publicKey: base64PublicKey,
// Optional: set the platform as a default name for the credential
// (example: "Pixel 7")
name: req.useragent.platform,
transports: response.response.transports,
passkey_user_id: user.passkey_user_id,
backed_up: registrationInfo.credentialBackedUp
});
// Kill the challenge for this session
delete req.session.challenge;
return res.json(user);
} catch (e) {
delete req.session.challenge;
console.error(e);
return res.status(400).send({ error: e.message });
}
});
Anhang: AuthenticatorAttestationResponse
AuthenticatorAttestationResponse
enthält zwei wichtige Objekte:
response.clientDataJSON
ist eine JSON-Version der Clientdaten. Dabei handelt es sich im Web um Daten, wie sie vom Browser erfasst werden. Sie enthält den RP-Ursprung, die Aufgabe undandroidPackageName
, wenn der Client eine Android-App ist. Als RP bietet Ihnen das Lesen vonclientDataJSON
Zugriff auf Informationen, die der Browser zum Zeitpunkt dercreate
-Anfrage gesehen hat.response.attestationObject
enthält zwei Informationen: <ph type="x-smartling-placeholder">- </ph>
attestationStatement
. Dies ist nur relevant, wenn Sie die Attestierung verwenden.authenticatorData
sind Daten, wie sie dem Passkey-Anbieter angezeigt werden. Als RP bietet Ihnen das Lesen vonauthenticatorData
Zugriff auf die Daten, die der Passkey-Anbieter sieht und zum Zeitpunkt dercreate
-Anfrage zurückgegeben wurde.
authenticatorData
enthält wichtige Informationen zu den Public-Key-Anmeldedaten, die dem neu erstellten Passkey zugeordnet sind:
- Die Anmeldedaten des öffentlichen Schlüssels selbst und eine eindeutige Ausweisdokument-ID dafür.
- Die mit dem Berechtigungsnachweis verknüpfte RP-ID.
- Flags, die den Nutzerstatus beim Erstellen des Passkeys beschreiben. Dazu gehört, ob ein Nutzer tatsächlich anwesend war und ob er erfolgreich bestätigt wurde (siehe
userVerification
). - AAGUID: Gibt den Passkey-Anbieter an. Es kann für Ihre Nutzer hilfreich sein, den Passkey-Anbieter aufzurufen, insbesondere wenn sie bei mehreren Passkey-Anbietern einen Passkey für Ihren Dienst registriert haben.
Obwohl authenticatorData
in attestationObject
verschachtelt ist, werden die darin enthaltenen Informationen für die Implementierung deines Passkeys benötigt – unabhängig davon, ob du die Bestätigung verwendest oder nicht. authenticatorData
ist codiert und enthält Felder, die in einem Binärformat codiert sind. Ihre serverseitige Bibliothek übernimmt normalerweise das Parsen und die Decodierung. Wenn du keine serverseitige Bibliothek verwendest, kannst du getAuthenticatorData()
clientseitig nutzen, um Arbeit serverseitig zu parsen und zu decodieren.
Anhang: Überprüfung der Registrierungsantwort
Intern umfasst die Überprüfung der Registrierungsantwort folgende Prüfungen:
- Achten Sie darauf, dass die RP-ID mit Ihrer Website übereinstimmt.
- Achten Sie darauf, dass der Ursprung der Anfrage ein erwarteter Ursprung für Ihre Website ist (Hauptwebsite-URL, Android-App).
- Wenn eine Nutzerbestätigung erforderlich ist, muss
authenticatorData.uv
true
lauten. Das FlagauthenticatorData.up
für die Nutzerpräsenz muss auftrue
gesetzt sein, da die Anwesenheit des Nutzers für Passkeys immer erforderlich ist. - Prüfen Sie, ob der Kunde die von Ihnen verlangte Aktion durchführen konnte. Wenn Sie keine Attestierung verwenden, ist diese Prüfung unwichtig. Die Implementierung dieser Prüfung hat sich jedoch bewährt. Sie stellt sicher, dass Ihr Code bereit ist, falls Sie sich später für die Verwendung der Attestierung entscheiden.
- Vergewissern Sie sich, dass die Berechtigungsnachweis-ID noch für keinen Nutzer registriert ist.
- Achten Sie darauf, dass der Algorithmus, der vom Passkey-Anbieter zum Erstellen der Anmeldedaten verwendet wird, einem von Ihnen im
alg
-Feld vonpublicKeyCredentialCreationOptions.pubKeyCredParams
aufgeführten Algorithmus entspricht. Dieser ist in der Regel in Ihrer serverseitigen Bibliothek definiert und für Sie nicht sichtbar. Dadurch wird sichergestellt, dass sich Nutzer nur mit Algorithmen registrieren können, die Sie zugelassen haben.
Weitere Informationen finden Sie im Quellcode für verifyRegistrationResponse
von SimpleWebAuthn oder in der vollständigen Liste der Überprüfungen in der Spezifikation.