Cette application Web est une démo pour ma bibliothèque de serveurs WebAuthn (fxamacker / webauthn). Il prend en charge l'enregistrement et l'authentification WebAuthn. Il met en œuvre l'API REST proposée pour les serveurs FIDO2.

WebAuthn (Authentification Web) est une norme Web W3C pour l'authentification des utilisateurs vers des applications et services Web. C'est un élément central de FIDO2, le successeur du protocole Ledo U2F Legacy.
Cette démo n'est pas pour une utilisation en production car elle est conçue pour être une démo.
go get github.com/fxamacker/webauthn-demo
$ CERTS_DIR=[folder containing cert.pem and key.pem] docker-compose up
La démonstration WebAuthn fonctionne sur https: // localhost: 8443 sur votre hôte docker.
$ docker-compose up
La démonstration WebAuthn fonctionne sur https: // localhost: 8443 sur votre hôte docker.
Le processus d'enregistrement se compose de deux étapes: créer des options de création d'identification et enregistrer les informations d'identification. Voir Signup.html, webauthn.register.js et enregistrement_handlers.go.
Créer des options de création d'identification:
Demande de manches /attestation/options de serveur en renvoyant des options de création d'identification (publicKeyCredentialCreationOptions) au client. Client utilise ensuite ces options avec navigator.credentials.create() pour créer de nouvelles informations d'identification.
// Simplified `/attestation/options` handler from registration_handlers.go
func (s *server) handleAttestationOptions(w http.ResponseWriter, r *http.Request) {
// Get user from datastore by username.
u, _ := s.dataStore.getUser(r.Context(), optionsRequest.Username)
// Create PublicKeyCredentialCreationOptions using webauthn library.
creationOptions, _ := webauthn.NewAttestationOptions(s.webAuthnConfig, &webauthn.User{ID: u.UserID, Name: u.UserName, DisplayName: u.DisplayName, CredentialIDs: u.CredentialIDs})
// Save creationOptions and user info in session to verify new credential later.
session.Values[WebAuthnCreationOptions] = creationOptions
session.Values[UserSession] = &userSession{User: u}
// Write creationOptions to response.
}
Enregistrer les informations d'identification:
Le serveur vérifie et enregistre les nouvelles informations d'identification reçues via /attestation/result .
// Simplified `/attestation/result` handler from registration_handlers.go
func (s *server) handleAttestationResult(w http.ResponseWriter, r *http.Request) {
// Get saved creationOptions and user info from session.
// Parse and verify credential in request body.
credentialAttestation, _ := webauthn.ParseAttestation(r.Body)
expected := &webauthn.AttestationExpectedData{
Origin: s.rpOrigin,
RPID: savedCreationOptions.RP.ID,
CredentialAlgs: credentialAlgs,
Challenge: base64.RawURLEncoding.EncodeToString(savedCreationOptions.Challenge),
UserVerification: savedCreationOptions.AuthenticatorSelection.UserVerification,
}
_, _, err = webauthn.VerifyAttestation(credentialAttestation, expected)
// Save user credential in datastore.
c := &credential{
CredentialID: credentialAttestation.RawID,
UserID: uSession.User.UserID,
Counter: credentialAttestation.AuthnData.Counter,
CoseKey: credentialAttestation.AuthnData.Credential.Raw,
}
err = s.dataStore.addUserCredential(r.Context(), uSession.User, c)
// Write "ok" response.
}
Le processus d'authentification nécessite deux étapes: créer des options de demande d'identification et vérifier les informations d'identification. Voir signin.html, webauthn.authn.js et authentication_handlers.go.
Créer des options de demande d'identification:
SERVER GRANDE /assertion/options Demande en renvoyant des options de demande d'identification (PublicKeyCredentialRequestoptions) au client. Client utilise ensuite ces options avec navigator.credentials.get() pour obtenir des informations d'identification existantes.
// Simplified `/assertion/options` handler from authentication_handlers.go
func (s *server) handleAssertionOptions(w http.ResponseWriter, r *http.Request) {
// Get user from datastore by username.
u, _ := s.dataStore.getUser(r.Context(), optionsRequest.Username)
// Create PublicKeyCredentialRequestOptions using webauthn library.
requestOptions, _ := webauthn.NewAssertionOptions(s.webAuthnConfig, &webauthn.User{ID: u.UserID, Name: u.UserName, DisplayName: u.DisplayName, CredentialIDs: u.CredentialIDs})
// Save requestOptions and user info in session to verify credential later.
session.Values[WebAuthnRequestOptions] = requestOptions
session.Values[UserSession] = &userSession{User: u}
// Write requestOptions to response.
}
Vérifiez les informations d'identification:
Le serveur vérifie les informations d'identification reçues via /asssertion/result .
// Simplified `/assertion/result` handler from authentication_handlers.go
func (s *server) handleAssertionResult(w http.ResponseWriter, r *http.Request) {
// Get saved requestOptions and user info.
// Parse credential in request body.
credentialAssertion, _ := webauthn.ParseAssertion(r.Body)
// Get credential from datastore by received credential ID.
c, _ := s.dataStore.getCredential(r.Context(), uSession.User.UserID, credentialAssertion.RawID)
// Verify credential.
expected := &webauthn.AssertionExpectedData{
Origin: s.rpOrigin,
RPID: savedRequestOptions.RPID,
Challenge: base64.RawURLEncoding.EncodeToString(savedRequestOptions.Challenge),
UserVerification: savedRequestOptions.UserVerification,
UserID: uSession.User.UserID,
UserCredentialIDs: userCredentialIDs,
PrevCounter: c.Counter,
Credential: credKey,
}
err = webauthn.VerifyAssertion(credentialAssertion, expected)
// Update authenticator counter in datastore.
c.Counter = credentialAssertion.AuthnData.Counter
err = s.dataStore.updateCredential(r.Context(), c)
// Write "ok" response.
}
Des correctifs de sécurité sont fournis pour la dernière version publiée.
Pour signaler les vulnérabilités de sécurité, veuillez envoyer un e-mail à [email protected] et autoriser le temps que le problème soit résolu avant de le signaler au public.
Copyright (c) 2019-présent Faye Amacker
FXAMACKER / WebAuthn-Demo est sous licence Apache, version 2.0. Voir la licence pour le texte complet de licence.