Aplikasi web ini adalah demo untuk perpustakaan server WebAuthn saya (FXAMACKER/WebAuthn). Ini mendukung pendaftaran dan otentikasi Webauthn. Ini mengimplementasikan API REST yang diusulkan untuk server FIDO2.

WebAuthn (Web Authentication) adalah standar Web W3C untuk mengotentikasi pengguna ke aplikasi dan layanan berbasis web. Ini adalah komponen inti dari FIDO2, penerus Protokol Legacy Fido U2F.
Demo ini bukan untuk penggunaan produksi karena dirancang untuk menjadi demo.
go get github.com/fxamacker/webauthn-demo
$ CERTS_DIR=[folder containing cert.pem and key.pem] docker-compose up
Demo WebAuthn berjalan di https: // localhost: 8443 di host Docker Anda.
$ docker-compose up
Demo WebAuthn berjalan di https: // localhost: 8443 di host Docker Anda.
Proses pendaftaran terdiri dari dua langkah: membuat opsi pembuatan kredensial dan mendaftarkan kredensial. Lihat penandatangan.html, webauthn.register.js, dan registrasi_handlers.go.
Buat opsi pembuatan kredensial:
Server Handles /attestation/options Permintaan dengan mengembalikan opsi pembuatan kredensial (PublicKeyCredentialCreationOptions) ke Klien. Klien kemudian menggunakan opsi -opsi tersebut dengan navigator.credentials.create() untuk membuat kredensial baru.
// 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.
}
Daftar Kredensial:
Server memverifikasi dan mendaftarkan kredensial baru yang diterima melalui /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.
}
Proses otentikasi membutuhkan dua langkah: Buat opsi permintaan kredensial dan verifikasi kredensial. Lihat Signin.html, webauthn.authn.js, dan authentication_handlers.go.
Buat Opsi Permintaan Kredensial:
Server Handles /assertion/options Permintaan dengan Mengembalikan Opsi Permintaan Kredensial (PublicKeyCredentialRequestOptions) ke Klien. Klien kemudian menggunakan opsi -opsi tersebut dengan navigator.credentials.get() untuk mendapatkan kredensial yang ada.
// 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.
}
Verifikasi Kredensial:
Server memverifikasi kredensial yang diterima melalui /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.
}
Perbaikan keamanan disediakan untuk versi terbaru yang dirilis.
Untuk melaporkan kerentanan keamanan, silakan kirim email ke [email protected] dan beri waktu untuk masalah yang akan diselesaikan sebelum melaporkannya kepada publik.
Hak Cipta (C) 2019-sekarang Faye Amacker
FXAMACKER/WEBAUTHN-DEMO dilisensikan di bawah lisensi Apache, versi 2.0. Lihat lisensi untuk teks lisensi lengkap.