Zum Inhalt springen
ecdsa.com
Python

py_webauthn

py_webauthn von Duo Labs, die Referenzbibliothek für WebAuthn-Relying-Partys in Python: Assertion-Signaturen nur als DER und strikte Zähler, aber die Benutzerverifizierung wird nur erzwungen, wenn du sie ausdrücklich verlangst.
Lizenz
BSD-3-Clause
Geprüfte Version
3.0.1 ·
Quellcode
github.com/duo-labs/py_webauthn
Dokumentation
duo-labs.github.io/py_webauthn/

Kompatibilität auf einen Blick

WebAuthn

py_webauthn (das Paket webauthn auf PyPI) erzeugt die Optionen für Registrierung und Authentifizierung und prüft die Antworten einschließlich aller Attestierungsformate, aufgebaut auf pyca/cryptography. Die Prüfung übergab der Bibliothek dieselbe Registrierung und dieselben Assertions eines Software-Authenticators wie bei SimpleWebAuthn, go-webauthn und WebAuthn4J – genau das macht die Unterschiede zwischen ihnen sichtbar.

Die Standardwerte der Richtlinie sind die lockersten der vier Bibliotheken. generate_registration_options() sendet überhaupt kein Element authenticatorSelection, sodass Browser auf Benutzerverifizierung preferred und Resident Keys discouraged zurückfallen – also auf Passkeys, die nicht auffindbar sind –, und verify_registration_response() und verify_authentication_response() akzeptierten Antworten mit nicht gesetztem UV-Flag, sofern nicht require_user_verification=True übergeben wird. Eine Anmeldung, die auf den Standardeinstellungen aufbaut, akzeptiert daher ein Antippen des Sicherheitsschlüssels ohne PIN. Lege die Richtlinie auf beiden Seiten explizit fest, wie es das Beispiel tut.

Assertion-Signaturen müssen ASN.1-DER sein: Eine rohe r‖s-Signatur mit 64 Byte scheiterte mit Could not verify authentication signature, einer Meldung, die die Kodierung nicht erwähnt; der Konverter DER ⇄ Raw zeigt, ob ein Test-Client die falsche Form erzeugt hat. Eine DER-Signatur mit High-S bestand die Prüfung. Standardmäßig werden Ed25519 (-8), ES256 (-7) und RS256 (-257) angeboten; anders als bei SimpleWebAuthn 14 gibt es keinen Eintrag für ML-DSA.

Die Zähler sind streng: Response sign count of 3 was not greater than current count of 5, ebenso bei 0 nach 5, während 0 nach 0 – das, was synchronisierte Passkeys melden – die Prüfung bestand. Speichere nach jeder erfolgreichen Anmeldung den zurückgegebenen Wert new_sign_count.

Dekodiere rohe Browserausgaben mit dem WebAuthn-Inspektor und experimentiere gefahrlos in der Passkey-Sandbox.

Fakten und die Prüfungen dahinter

Nichts im Folgenden ist aus einer Dokumentation abgeschrieben. Das Prüfskript content/libraries/verify/py-webauthn/run.sh hat py_webauthn 3.0.1 am 20. Oktober 2026 im Container-Image python:3.14.8-slim-trixie ausgeführt; die Seite muss mit seiner Ausgabe übereinstimmen, und jeder Fakt führt die zugehörigen Zeilen auf.

  • Standard-COSE-Algorithmen

    -8-7-257

    generate_registration_options() listet die COSE-Algorithmen -8 (Ed25519), -7 (ES256) und -257 (RS256) auf.

    Von der Prüfung aufgezeichnet
    fact webauthn-default-algorithms = -8, -7, -257
  • Standard-Attestierung

    none

    Die Übermittlung der Attestierung steht standardmäßig auf none.

    Von der Prüfung aufgezeichnet
    fact webauthn-attestation = none
  • Standard-Benutzerverifizierung

    preferred

    Standardmäßig wird kein authenticatorSelection gesendet, sodass der Browser den WebAuthn-Standardwert preferred anwendet.

    Von der Prüfung aufgezeichnet
    fact webauthn-user-verification = preferred
    evidence webauthn-user-verification: authenticatorSelection in the generated options: absent
  • Standardwert für Resident Key

    discouraged

    Ohne authenticatorSelection gilt der WebAuthn-Standardwert discouraged, sodass Authenticators nicht aufgefordert werden, Discoverable Credentials zu erzeugen.

    Von der Prüfung aufgezeichnet
    fact webauthn-resident-key = discouraged
  • Benutzerverifizierung standardmäßig erzwungen

    no

    Eine Registrierung und eine Assertion, bei denen nur UP gesetzt war, bestanden die Prüfung; mit require_user_verification=True scheiterte die Assertion mit User verification is required but user was not verified during authentication.

    Von der Prüfung aufgezeichnet
    fact webauthn-uv-enforced-by-default = no
    evidence webauthn-uv-enforced-by-default: registration with the UV flag clear: verified
  • 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 InvalidAuthenticationResponse: Could not verify authentication signature.

    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

    Die Zählerstände 3 und 0 nach einer gespeicherten 5 scheiterten mit Response sign count of … was not greater than current count of 5; 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 Optionen für Registrierung und Authentifizierung, die Benutzerverifizierung und ein Discoverable Credential verlangen, statt die Standardeinstellungen der Bibliothek zu übernehmen.
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"])

Die Snippet-Testumgebung führt jedes Beispiel unverändert im Container-Image python:3.14.8-slim-trixie aus, und der Lauf schlägt fehl, wenn die Ausgabe nicht übereinstimmt.

Einrichtung
pip install --quiet --root-user-action=ignore webauthn==3.0.1
Befehl
python usage.py
Ausgabe muss passen (regulärer Ausdruck)
uv: required required\nresident key: required

Bibliotheken