Esta aplicación web es una demostración para mi biblioteca de servidor webauthn (fxamacker/webauthn). Admite el registro y la autenticación de WebAuthn. Implementa la API REST propuesta para los servidores FIDO2.

WebAuthn (Autenticación web) es un estándar web W3C para autenticar a los usuarios a aplicaciones y servicios basados en la web. Es un componente central de FIDO2, el sucesor del protocolo Legacy FIDO U2F.
Esta demostración no es para uso de producción porque está diseñado para ser una demostración.
go get github.com/fxamacker/webauthn-demo
$ CERTS_DIR=[folder containing cert.pem and key.pem] docker-compose up
La demostración de WebAuthn se ejecuta en https: // localhost: 8443 en su host de Docker.
$ docker-compose up
La demostración de WebAuthn se ejecuta en https: // localhost: 8443 en su host de Docker.
El proceso de registro consta de dos pasos: crear opciones de creación de credenciales y registrar credenciales. Ver registro.html, webauthn.register.js y registro_handlers.go.
Crear opciones de creación de credenciales:
Solicitud de manejo /attestation/options del servidor devolviendo opciones de creación de credenciales (publickeyCredentialCreationOptions) al cliente. El cliente luego usa esas opciones con navigator.credentials.create() para crear nuevas credenciales.
// 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.
}
Registre las credenciales:
El servidor verifica y registra nuevas credenciales recibidas a través de /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.
}
El proceso de autenticación requiere dos pasos: crear opciones de solicitud de credenciales y verificar las credenciales. Consulte Signin.html, WebAuthn.authn.js y autenticación_handlers.go.
Crear opciones de solicitud de credencial:
Solicitud de manejo /assertion/options del servidor devolviendo las opciones de solicitud de credenciales (PublicKeyCredentialRequestOptions) al cliente. El cliente luego usa esas opciones con navigator.credentials.get() para obtener las credenciales existentes.
// 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.
}
Verificar credenciales:
El servidor verifica las credenciales recibidas a través de /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.
}
Se proporcionan correcciones de seguridad para la última versión lanzada.
Para informar vulnerabilidades de seguridad, envíe un correo electrónico a [email protected] y deje tiempo para que el problema se resuelva antes de informarlo al público.
Copyright (c) 2019-presente Faye Amacker
Fxamacker/WebAuthn-Demo tiene licencia bajo la licencia Apache, versión 2.0. Vea la licencia para el texto completo de la licencia.