Aller au contenu
ecdsa.com
Python

py_webauthn

py_webauthn de Duo Labs, la bibliothèque WebAuthn de référence côté partie de confiance en Python : signatures d’assertion DER uniquement et compteurs stricts, mais la vérification de l’utilisateur n’est imposée que si vous la demandez.
Licence
BSD-3-Clause
Version vérifiée
3.0.1 ·
Code source
github.com/duo-labs/py_webauthn
Documentation
duo-labs.github.io/py_webauthn/

Compatibilité en un coup d’œil

WebAuthn

py_webauthn (le paquet webauthn sur PyPI) génère les options d’enregistrement et d’authentification et vérifie les réponses, tous formats d’attestation compris, en s’appuyant sur pyca/cryptography. Les essais lui ont fourni le même enregistrement et les mêmes assertions, issus d’un authentificateur logiciel, que pour SimpleWebAuthn, go-webauthn et WebAuthn4J, ce qui fait ressortir les différences entre elles.

Ses politiques par défaut sont les plus permissives des quatre. generate_registration_options() n’envoie aucun membre authenticatorSelection, si bien que les navigateurs se rabattent sur la vérification de l’utilisateur preferred et les clés résidentes discouraged (des clés d’accès non détectables), et verify_registration_response() et verify_authentication_response() ont accepté des réponses dont l’indicateur UV n’était pas positionné, sauf si require_user_verification=True est passé. Une connexion construite sur les valeurs par défaut accepte donc un simple appui sur une clé de sécurité, sans PIN. Définissez explicitement la politique des deux côtés, comme le fait l’exemple.

Les signatures d’assertion doivent être en ASN.1 DER : une signature r‖s brute de 64 octets a échoué avec Could not verify authentication signature, un message qui ne mentionne pas l’encodage ; le convertisseur DER ⇄ brut indique si un client de test a produit la mauvaise forme. Une signature DER high-S a été vérifiée. Ed25519 (-8), ES256 (-7) et RS256 (-257) sont proposés par défaut ; il n’y a pas d’entrée ML-DSA, contrairement à SimpleWebAuthn 14.

Les compteurs sont stricts : Response sign count of 3 was not greater than current count of 5, même erreur pour 0 après 5, tandis que 0 après 0 (ce que renvoient les clés d’accès synchronisées) a été vérifié. Enregistrez le new_sign_count renvoyé après chaque connexion réussie.

Décodez la sortie brute du navigateur avec l’inspecteur WebAuthn et expérimentez sans risque dans le bac à sable des clés d’accès.

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/py-webauthn/run.sh a exécuté py_webauthn 3.0.1 dans l’image de conteneur python:3.14.8-slim-trixie le 20 octobre 2026 ; la page doit correspondre à ce que la vérification a affiché, et chaque fait cite les lignes en question.

  • Algorithmes COSE par défaut

    -8-7-257

    generate_registration_options() liste les algorithmes COSE -8 (Ed25519), -7 (ES256) et -257 (RS256).

    Relevé par la vérification
    fact webauthn-default-algorithms = -8, -7, -257
  • Attestation par défaut

    none

    La transmission de l’attestation vaut none par défaut.

    Relevé par la vérification
    fact webauthn-attestation = none
  • Vérification de l’utilisateur par défaut

    preferred

    Aucun authenticatorSelection n’est envoyé par défaut : le navigateur applique donc la valeur par défaut de WebAuthn, preferred.

    Relevé par la vérification
    fact webauthn-user-verification = preferred
    evidence webauthn-user-verification: authenticatorSelection in the generated options: absent
  • Clé résidente par défaut

    discouraged

    Sans authenticatorSelection, la valeur par défaut de WebAuthn, discouraged, s’applique : les authentificateurs ne sont donc pas invités à créer des identifiants détectables.

    Relevé par la vérification
    fact webauthn-resident-key = discouraged
  • Vérification de l’utilisateur exigée par défaut

    no

    Un enregistrement et une assertion où seul UP était positionné ont été vérifiés ; avec require_user_verification=True, l’assertion a échoué avec User verification is required but user was not verified during authentication.

    Relevé par la vérification
    fact webauthn-uv-enforced-by-default = no
    evidence webauthn-uv-enforced-by-default: registration with the UV flag clear: verified
  • 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 InvalidAuthenticationResponse: Could not verify authentication signature.

    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

    Les compteurs 3 et 0 après un 5 enregistré ont échoué avec Response sign count of … was not greater than current count of 5 ; 0 après un 0 enregistré a été vérifié.

    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

Générer des options d’enregistrement et d’authentification qui exigent la vérification de l’utilisateur et un identifiant détectable, au lieu des valeurs par défaut de la bibliothèque.
import json

from webauthn import generate_authentication_options, generate_registration_options, options_to_json
from webauthn.helpers.structs import AuthenticatorSelectionCriteria, ResidentKeyRequirement, UserVerificationRequirement

# The defaults send no authenticatorSelection at all, and verification does not
# require UV. State the policy in the options, and pass
# require_user_verification=True to verify_registration_response() and
# verify_authentication_response() so the server enforces the same policy.
registration = generate_registration_options(
    rp_id="example.com",
    rp_name="Example",
    user_name="user@example.com",
    authenticator_selection=AuthenticatorSelectionCriteria(
        resident_key=ResidentKeyRequirement.REQUIRED,
        user_verification=UserVerificationRequirement.REQUIRED,
    ),
)
authentication = generate_authentication_options(rp_id="example.com", user_verification=UserVerificationRequirement.REQUIRED)

selection = json.loads(options_to_json(registration))["authenticatorSelection"]
print("uv:", selection["userVerification"], json.loads(options_to_json(authentication))["userVerification"])
print("resident key:", selection["residentKey"])

Le banc de test des extraits de code exécute chaque exemple tel quel dans l’image de conteneur python:3.14.8-slim-trixie, et l’exécution échoue si la sortie ne correspond pas.

Mise en place
pip install --quiet --root-user-action=ignore webauthn==3.0.1
Commande
python usage.py
La sortie doit correspondre à cette expression régulière
uv: required required\nresident key: required

Bibliothèques