Zum Inhalt springen
ecdsa.com
Java · Kotlin

WebAuthn4J

WebAuthn4J, die Bibliothek für die WebAuthn-Prüfung, auf der die Passkey-Unterstützung von Spring Security und Keycloak aufbaut: keine versteckten Standardwerte für die Benutzerverifizierung, nur DER-Signaturen und ein harter Fehler, wenn der Zähler zurückgeht.
Lizenz
Apache-2.0
Geprüfte Version
0.31.11.RELEASE ·
Quellcode
github.com/webauthn4j/webauthn4j
Dokumentation
webauthn4j.github.io/webauthn4j/en/

Kompatibilität auf einen Blick

WebAuthn

WebAuthn4J prüft Registrierungs- und Authentifizierungsantworten – Attestierungen in jedem Format, COSE-Schlüssel, Flags, Zähler und Signaturen – und überlässt das Erstellen der Optionen der Relying Party. Spring Security und Keycloak nutzen die Bibliothek intern. Version 0.31.11 hängt von Jackson 3 (tools.jackson.*) ab; das spielt eine Rolle, wenn deine Anwendung für ihr eigenes JSON noch com.fasterxml.jackson aus Jackson 2 verwendet. Außerdem trägt die API der Bibliothek die Annotationen @NotNull von JetBrains: Das Kompilieren gegen WebAuthn4J mit dem Einzeldatei-Launcher java scheiterte, bis org.jetbrains:annotations im Classpath lag.

Eine Standardrichtlinie für die Benutzerverifizierung, die du vergessen könntest, gibt es nicht: RegistrationParameters und AuthenticationParameters nehmen userVerificationRequired und userPresenceRequired als Pflichtargumente entgegen. Im Test bestanden eine Registrierung und eine Assertion mit nicht gesetztem UV-Flag die Prüfung, wenn false übergeben wurde, und scheiterten bei true mit UserNotVerifiedException. Halte den Wert konsistent mit dem userVerification, das du in den Optionen sendest, wie es das Beispiel zeigt.

Signaturen müssen ASN.1-DER sein: Eine rohe r‖s-Signatur mit 64 Byte in einer Assertion scheiterte mit BadSignatureException: Assertion signature is not valid., und eine DER-Signatur mit High-S bestand die Prüfung. Ein Zähler unter dem gespeicherten Wert lässt die Anmeldung mit MaliciousCounterValueException: Malicious counter value is detected. Cloned authenticators exist in parallel. scheitern, während ein Zähler, der immer 0 war, wie ihn synchronisierte Passkeys melden, die Prüfung besteht. Ed25519-Credentials funktionierten durchgängig, von der Registrierung bis zur Prüfung.

createNonStrictWebAuthnManager() akzeptiert jede Attestierung, ohne sie gegen Vertrauensanker zu prüfen. Das ist richtig, wenn du die Attestierung none anforderst, und falsch, wenn die Attestierung eine Richtlinienentscheidung ist; konfiguriere in diesem Fall Vertrauensanker und verwende einen strikten Manager.

Der WebAuthn-Inspektor dekodiert, was Browser senden, und der AAGUID-Lookup identifiziert Authenticator-Modelle für Attestierungsrichtlinien.

Fakten und die Prüfungen dahinter

Nichts im Folgenden ist aus einer Dokumentation abgeschrieben. Das Prüfskript content/libraries/verify/webauthn4j/run.sh hat WebAuthn4J 0.31.11.RELEASE am 20. Oktober 2026 im Container-Image maven:3.9.16-eclipse-temurin-25 ausgeführt; die Seite muss mit seiner Ausgabe übereinstimmen, und jeder Fakt führt die zugehörigen Zeilen auf.

  • Argument für Benutzerverifizierung

    mandatory

    userVerificationRequired und userPresenceRequired sind Pflichtargumente des Konstruktors; mit false bestanden Antworten ohne UV-Flag die Prüfung, mit true scheiterten sie mit UserNotVerifiedException.

    Von der Prüfung aufgezeichnet
    fact uv-requirement-argument = mandatory
    evidence uv-requirement-argument: registration with UV clear, userVerificationRequired false: verified; true: UserNotVerifiedException: Verifier is configured to check user verified, but UV flag in authenticatorData is not set.
    evidence uv-requirement-argument: RegistrationParameters and AuthenticationParameters take userVerificationRequired and userPresenceRequired as required booleans
  • Kodierung der Assertion-Signatur

    der

    Eine korrekte ES256-Assertion mit DER-Signatur bestand die Prüfung.

    Von der Prüfung aufgezeichnet
    fact webauthn-assertion-encoding = der
  • Assertion-Signatur als rohes r‖s

    rejected

    Eine rohe r‖s-Signatur mit 64 Byte scheiterte mit BadSignatureException: Assertion signature is not valid.

    Von der Prüfung aufgezeichnet
    fact webauthn-raw-signature = rejected
  • Assertion-Signatur mit High-S

    accepted

    Eine DER-Signatur, in der s durch n − s ersetzt war, bestand die Prüfung.

    Von der Prüfung aufgezeichnet
    fact webauthn-high-s = accepted
  • Rückläufiger Signaturzähler

    rejected

    Ein Zählerstand von 3 nach einer gespeicherten 5 scheiterte mit MaliciousCounterValueException; 0 nach einer gespeicherten 0 bestand die Prüfung.

    Von der Prüfung aufgezeichnet
    fact webauthn-counter-regression = rejected
  • Ed25519-Credentials

    supported

    Ein Ed25519-Credential (COSE -8) ließ sich erfolgreich registrieren und zur Authentifizierung verwenden.

    Von der Prüfung aufgezeichnet
    fact webauthn-ed25519 = supported
    evidence webauthn-ed25519: verified

Verwendung

Erzeuge einen WebAuthn-Manager für die Prüfung und Registrierungsparameter, die die Anforderungen an Benutzerverifizierung und Benutzeranwesenheit ausdrücklich festlegen.
import com.webauthn4j.WebAuthnManager;
import com.webauthn4j.data.RegistrationParameters;
import com.webauthn4j.data.PublicKeyCredentialParameters;
import com.webauthn4j.data.PublicKeyCredentialType;
import com.webauthn4j.data.attestation.statement.COSEAlgorithmIdentifier;
import com.webauthn4j.data.client.Origin;
import com.webauthn4j.data.client.challenge.DefaultChallenge;
import com.webauthn4j.server.ServerProperty;
import java.util.List;

public class Usage {
    public static void main(String[] args) {
        // "Non-strict" accepts every attestation format without trust anchors; pair it
        // with attestation "none" in the options, or configure trust anchors instead.
        WebAuthnManager manager = WebAuthnManager.createNonStrictWebAuthnManager();
        ServerProperty server = new ServerProperty(new Origin("https://example.com"), "example.com", new DefaultChallenge());

        // There is no default: every verification states UV and UP requirements explicitly.
        RegistrationParameters registration = new RegistrationParameters(server,
            List.of(new PublicKeyCredentialParameters(PublicKeyCredentialType.PUBLIC_KEY, COSEAlgorithmIdentifier.ES256)),
            true, true);
        // manager.verify(manager.parseRegistrationResponseJSON(json), registration) does the rest.
        System.out.println("uv required: " + registration.isUserVerificationRequired()
            + ", up required: " + registration.isUserPresenceRequired() + ", manager: " + manager.getClass().getSimpleName());
    }
}

Die Snippet-Testumgebung führt jedes Beispiel unverändert im Container-Image maven:3.9.16-eclipse-temurin-25 aus, und der Lauf schlägt fehl, wenn die Ausgabe nicht übereinstimmt.

Einrichtung
mvn -q -B dependency:copy-dependencies -DoutputDirectory=lib >/dev/null
Befehl
java -cp 'lib/*' Usage.java
Ausgabe muss passen (regulärer Ausdruck)
uv required: true, up required: true, manager: WebAuthnManager

Bibliotheken