Aller au contenu
ecdsa.com
Java · Kotlin

WebAuthn4J

WebAuthn4J, la bibliothèque de vérification WebAuthn sur laquelle reposent Keycloak et la prise en charge des clés d’accès de Spring Security : aucune valeur par défaut cachée pour la vérification de l’utilisateur, des signatures DER uniquement et un échec net en cas de régression du compteur.
Licence
Apache-2.0
Version vérifiée
0.31.11.RELEASE ·
Code source
github.com/webauthn4j/webauthn4j
Documentation
webauthn4j.github.io/webauthn4j/en/

Compatibilité en un coup d’œil

WebAuthn

WebAuthn4J vérifie les réponses d’enregistrement et d’authentification (déclarations d’attestation de tous formats, clés COSE, indicateurs, compteurs et signatures) et laisse à la partie de confiance (relying party) le soin de construire les options. Spring Security et Keycloak s’appuient dessus. La version 0.31.11 dépend de Jackson 3 (tools.jackson.*), ce qui compte si votre application utilise encore le com.fasterxml.jackson de Jackson 2 pour son propre JSON, et son API porte des annotations JetBrains @NotNull : la compilation avec le lanceur java à fichier unique a échoué tant que org.jetbrains:annotations n’était pas dans le classpath.

Il n’existe pas de politique par défaut de vérification de l’utilisateur que l’on pourrait oublier : RegistrationParameters et AuthenticationParameters prennent userVerificationRequired et userPresenceRequired comme arguments obligatoires. Lors de la vérification, un enregistrement et une assertion sans l’indicateur UV ont été acceptés quand false était passé et ont échoué avec UserNotVerifiedException quand c’était true. Gardez cette valeur cohérente avec le userVerification que vous envoyez dans les options, comme le montre l’exemple.

Les signatures doivent être en ASN.1 DER : une signature d’assertion r‖s brute de 64 octets a échoué avec BadSignatureException: Assertion signature is not valid., et une signature DER high-S a été vérifiée. Un compteur inférieur à la valeur enregistrée fait échouer la connexion avec MaliciousCounterValueException: Malicious counter value is detected. Cloned authenticators exist in parallel., tandis qu’un compteur resté à 0 depuis le début, comme en renvoient les clés d’accès synchronisées, est accepté. Les identifiants Ed25519 ont été vérifiés de bout en bout.

createNonStrictWebAuthnManager() accepte n’importe quelle déclaration d’attestation sans la contrôler par rapport à des ancres de confiance, ce qui convient quand vous demandez l’attestation none, mais pas quand l’attestation relève d’une décision de politique ; dans ce cas, configurez des ancres de confiance et utilisez un gestionnaire strict.

L’inspecteur WebAuthn décode ce qu’envoient les navigateurs, et la recherche d’AAGUID identifie les modèles d’authentificateurs pour les politiques d’attestation.

Les faits et les vérifications qui les fondent

Rien de ce qui suit n’est copié d’une documentation. La vérification content/libraries/verify/webauthn4j/run.sh a exécuté WebAuthn4J 0.31.11.RELEASE dans l’image de conteneur maven:3.9.16-eclipse-temurin-25 le 20 octobre 2026 ; la page doit correspondre à ce que la vérification a affiché, et chaque fait cite les lignes en question.

  • Argument de vérification de l’utilisateur

    mandatory

    userVerificationRequired et userPresenceRequired sont des arguments obligatoires du constructeur ; avec false, les réponses sans l’indicateur UV ont passé la vérification, avec true elles ont échoué avec UserNotVerifiedException.

    Relevé par la vérification
    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
  • Encodage de la signature d’assertion

    der

    Une assertion ES256 correcte avec une signature DER a été vérifiée.

    Relevé par la vérification
    fact webauthn-assertion-encoding = der
  • Signature d’assertion r‖s brute

    rejected

    Une signature r‖s brute de 64 octets a échoué avec BadSignatureException: Assertion signature is not valid.

    Relevé par la vérification
    fact webauthn-raw-signature = rejected
  • Signature d’assertion high-S

    accepted

    Une signature DER dont s a été remplacé par n − s a été vérifiée.

    Relevé par la vérification
    fact webauthn-high-s = accepted
  • Compteur de signatures qui recule

    rejected

    Un compteur à 3 après une valeur enregistrée de 5 a échoué avec MaliciousCounterValueException ; 0 après un 0 enregistré a été accepté.

    Relevé par la vérification
    fact webauthn-counter-regression = rejected
  • Identifiants Ed25519

    supported

    Un identifiant Ed25519 (COSE -8) a été enregistré et authentifié avec succès.

    Relevé par la vérification
    fact webauthn-ed25519 = supported
    evidence webauthn-ed25519: verified

Utilisation

Créer un gestionnaire de vérification et des paramètres d’enregistrement qui énoncent explicitement les exigences de vérification de l’utilisateur et de présence de l’utilisateur.
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());
    }
}

Le banc de test des extraits de code exécute chaque exemple tel quel dans l’image de conteneur maven:3.9.16-eclipse-temurin-25, et l’exécution échoue si la sortie ne correspond pas.

Mise en place
mvn -q -B dependency:copy-dependencies -DoutputDirectory=lib >/dev/null
Commande
java -cp 'lib/*' Usage.java
La sortie doit correspondre à cette expression régulière
uv required: true, up required: true, manager: WebAuthnManager

Bibliothèques