WebAuthn (Web Authentication API) ist ein W3C-Standard, der eine sichere passwortlose Authentifizierung mit Public-Key-Kryptografie ermöglicht. Anstelle von Passwörtern registrieren und authentifizieren sich Benutzer mit hardwarebasierten Authentifikatoren (wie Fingerabdrucklesern, Face ID, YubiKeys usw.) oder Plattform-Authentifikatoren (integriert, wie Touch ID).
Unten finden Sie, wie Sie die Registrierung und Authentifizierung mit einem JavaScript-Client behandeln.
Wie die WebAuthn-Registrierung funktioniert
Benutzer initiiert die Registrierung:
Der Benutzer gibt einen Benutzernamen ein und klickt auf Register.
Browser fordert Optionen vom Server an:
Das Frontend stellt eine POST-Anfrage, um Registrierungsoptionen abzurufen.
Browser erstellt Credentials:
Mit der navigator.credentials.create()-API über SimpleWebAuthnBrowser.startRegistration() wird ein Credential erstellt.
Server verifiziert Registrierung:
Der Browser sendet die Anmeldeinformationen an den Server zurück.
Der Server verifiziert die Registrierung und speichert den öffentlichen Schlüssel für diesen Benutzer.
Die Komponente TsgcWSAPIServer_WebAuthn verfügt über eine HTML-Datei zum Testen des WebAuthn-Protokolls. Diese HTML-Datei enthält eine minimale UI und JavaScript zur Interaktion mit WebAuthn.
Walkthrough von sgcWebAuthn.html
Strukturübersicht:
Username-Eingabe: Erfasst den Bezeichner des Benutzers.
Buttons:
Register – leitet die WebAuthn-Registrierung ein.
Authenticate – leitet die Anmeldung ein (wird ähnlich behandelt).
Debug Console: Zeigt Echtzeit-Debug-Informationen an (JSON von WebAuthn).
1. HTML-UI für die Eingabe
<input type="text" id="username" name="username" autocomplete="username webauthn" />
<button id="btnRegBegin"><strong>Register</strong></button>
2. JavaScript: Button-Klick-Handler
document.querySelector('#btnRegBegin').addEventListener('click', async () => {
const username = document.getElementById("username").value;
if (username == "") {
document.getElementById('Error').innerText = 'Please enter a username to register';
return;
}
const resp = await fetch('<#webauthn_registration_options>', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ username, algorithms: [] })
});
const options = await resp.json();
const attResp = await startRegistration(options); // WebAuthn API
3. Server Response (Fake Endpoint in HTML)
fetch('/sgcWebAuthn/Registration/Options', ...)
fetch('/sgcWebAuthn/Registration/Verify', ...)
4. Abschluss der Registrierung
const verificationResp = await fetch('/webauthn/register/verify', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(attResp)
});
const verificationJSON = await verificationResp.json();
if (verificationJSON && verificationJSON.verified) {
document.getElementById('Success').innerHTML = `Authenticator registered!`;
}
Wie die WebAuthn-Authentifizierung funktioniert
Benutzer initiiert die Authentifizierung:
Der Benutzer gibt einen Benutzernamen ein und klickt auf Register.
Browser fordert Optionen vom Server an:
Das Frontend stellt eine POST-Anforderung, um Authentifizierungsoptionen zu erhalten.
Browser erstellt Credentials:
Verwendung der navigator.credentials.get()-API über SimpleWebAuthnBrowser.startAuthentication().
Server überprüft die Authentifizierung:
Der Browser sendet das Anmeldedatum an den Server zurück.
Der Server überprüft das signierte Ergebnis.
1. HTML-UI-Einrichtung
<div class="container">
<h1>WebAuthn Authentication Sample</h1>
<section id="userdata">
<label for="username">Username:</label>
<input type="text" id="username" name="username" autocomplete="username webauthn" autofocus />
</section>
<button id="btnAuthBegin"><strong>Authenticate</strong></button>
<p id="Success" class="success"></p>
<p id="Error" class="error"></p>
<details open>
<summary>Console</summary>
<textarea id="Debug"></textarea>
</details>
</div>
2. Authentifizierungsoptionen abrufen
Bevor Sie startAuthentication aufrufen, senden Sie den Benutzernamen an den Server
const resp = await fetch('<#webauthn_authentication_options>', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
username: document.getElementById("username").value,
user_verification: 'preferred'
}),
});
Der Server antwortet mit einem JSON-Objekt, das Folgendes enthält:
{
"challenge": "base64url-encoded-random-string",
"allowCredentials": [
{
"id": "base64url-credential-id",
"type": "public-key"
}
],
"userVerification": "preferred",
"rpId": "yourdomain.com"
}
Dies wird als PublicKeyCredentialRequestOptions bezeichnet.
3. Die Authenticator-Antwort empfangen
Die asseResp sieht so aus (vereinfacht):
{
"id": "credentialId",
"rawId": "base64url-encoded-id",
"response": {
"authenticatorData": "...",
"clientDataJSON": "...",
"signature": "...",
"userHandle": "..."
},
"type": "public-key",
"clientExtensionResults": {}
}
Diese Antwort beweist, dass der Benutzer:
4. Senden Sie die signierte Authentifizierungsantwort an den Server
Nachdem der Benutzer mit seinem Authenticator interagiert hat (über startAuthentication()), erhalten Sie ein Response-Objekt in JavaScript.
const verificationResp = await fetch('/webauthn/authenticate/verify', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(asseResp), // this is the signed response
});
5. Holen Sie die Antwort des Servers
Der Server antwortet mit einem Ergebnis wie diesem:
{ "verified": true }
Oder falls etwas schiefgegangen ist:
{ "verified": false, "error": "Invalid signature" }
Und Sie behandeln es in Ihrem Frontend-Code:
const result = await verificationResp.json();
if (result.verified) {
document.getElementById('Success').textContent = 'User authenticated!';
} else {
document.getElementById('Error').textContent = 'Authentication failed!';
}