Pular para o conteúdo
ecdsa.com
Go

go-webauthn

O go-webauthn, a biblioteca WebAuthn do lado da parte confiável (relying party) para Go: assinaturas de asserção apenas em DER, verificação do usuário ditada pela sessão e retrocessos do contador informados como aviso de clonagem, e não como falha de login.
Licença
BSD-3-Clause
Versão verificada
0.18.2 ·
Código-fonte
github.com/go-webauthn/webauthn
Documentação
pkg.go.dev/github.com/go-webauthn/webauthn/webauthn

Visão geral da compatibilidade

WebAuthn

github.com/go-webauthn/webauthn (o fork mantido do duo-labs/webauthn) executa as duas cerimônias — BeginRegistration/FinishRegistration e BeginLogin/FinishLogin, ou as variantes Validate* para outros frameworks além do net/http — e verifica todos os formatos de atestado. O teste validou as mesmas respostas de autenticador em software usadas para o SimpleWebAuthn, o py_webauthn e o WebAuthn4J.

A política vem da configuração e é transportada em SessionData. Com um AuthenticatorSelection vazio, BeginRegistration enviou um objeto vazio, então os navegadores aplicam os padrões — verificação do usuário preferred, chave residente discouraged — e a validação aceitou respostas sem a flag UV porque a sessão pedia apenas preferred. Com UserVerification: required na sessão, a mesma asserção falhou com User verification required but flag not set by authenticator. Defina a política em Config.AuthenticatorSelection, como faz o exemplo, e armazene o SessionData inteiro entre as duas chamadas.

O tratamento do contador é a diferença mais importante em relação às outras bibliotecas. O login com uma asserção cujo contador (3) era menor que o armazenado (5) foi bem-sucedido: a credencial retornada veio com Authenticator.CloneWarning definido e com o SignCount mantido em 5. A biblioteca apenas informa um possível clone; recusar ou não o login cabe ao seu código, que deve verificar CloneWarning depois de cada login.

As assinaturas de asserção precisam estar em ASN.1 DER — uma assinatura r‖s bruta de 64 bytes falhou com Error validating the assertion signature: Signature invalid or not provided —, e uma assinatura DER high-S foi verificada. A lista padrão de pubKeyCredParams é longa: ES256, ES384 e ES512 (-7, -35, -36), RS256 a RS512 (-257 a -259), PS256 a PS512 (-37 a -39) e Ed25519 (-8); a credencial Ed25519 foi verificada de ponta a ponta. Não há entrada para ML-DSA na versão 0.18.2.

Decodifique o que um navegador envia com o inspetor de WebAuthn, consulte modelos de autenticador com a consulta de AAGUID e experimente as cerimônias no ambiente de testes de chaves de acesso.

Os fatos e as verificações por trás deles

Nada abaixo foi copiado da documentação. A verificação content/libraries/verify/go-webauthn/run.sh executou go-webauthn 0.18.2 na imagem de contêiner golang:1.27.3-trixie em 20 de outubro de 2026; a página precisa corresponder ao que a verificação imprimiu, e cada fato lista essas linhas.

  • Algoritmos COSE padrão

    -7-35-36-257-258-259-37-38-39-8

    BeginRegistration lista os algoritmos COSE -7, -35, -36 (ES256/384/512), -257, -258, -259 (RS256/384/512), -37, -38, -39 (PS256/384/512) e -8 (Ed25519).

    Registrado pela verificação
    fact webauthn-default-algorithms = -7, -35, -36, -257, -258, -259, -37, -38, -39, -8
  • Atestado padrão

    none

    A preferência de transmissão do atestado (attestation conveyance) é none por padrão.

    Registrado pela verificação
    fact webauthn-attestation = none
  • Nível padrão de verificação do usuário

    preferred

    Por padrão, authenticatorSelection é enviado como um objeto vazio, então o navegador aplica preferred.

    Registrado pela verificação
    fact webauthn-user-verification = preferred
    evidence webauthn-user-verification: authenticatorSelection in BeginRegistration output: {}
  • Configuração padrão de chave residente

    discouraged

    Sem residentKey nas opções, vale o padrão do WebAuthn, discouraged.

    Registrado pela verificação
    fact webauthn-resident-key = discouraged
  • Verificação do usuário exigida por padrão

    no

    Com a verificação do usuário da sessão em preferred, um registro e uma asserção só com a flag UP foram verificados; com required, a asserção falhou com User verification required but flag not set by authenticator.

    Registrado pela verificação
    fact webauthn-uv-enforced-by-default = no
    evidence webauthn-uv-enforced-by-default: registration with the UV flag clear, session UV preferred: verified
  • Codificação da assinatura de asserção

    der

    Uma asserção ES256 correta com assinatura DER foi verificada.

    Registrado pela verificação
    fact webauthn-assertion-encoding = der
  • Assinatura de asserção r‖s bruta

    rejected

    Uma assinatura r‖s bruta de 64 bytes falhou com Error validating the assertion signature: Signature invalid or not provided.

    Registrado pela verificação
    fact webauthn-raw-signature = rejected
  • Assinatura de asserção high-S

    accepted

    Uma assinatura DER com s substituído por n − s foi verificada.

    Registrado pela verificação
    fact webauthn-high-s = accepted
  • Contador de assinaturas que retrocede

    flagged

    Um contador 3 depois de um 5 armazenado não fez o login falhar: a credencial voltou com CloneWarning verdadeiro e SignCount ainda em 5.

    Registrado pela verificação
    fact webauthn-counter-regression = flagged
    evidence webauthn-counter-regression: counter 3 after a stored 5: login succeeded, CloneWarning true, SignCount now 5
    evidence webauthn-counter-regression: counter 0 after a stored 0: verified, CloneWarning false
  • Credenciais Ed25519

    supported

    Uma credencial Ed25519 (COSE -8) foi registrada e autenticada com sucesso.

    Registrado pela verificação
    fact webauthn-ed25519 = supported
    evidence webauthn-ed25519: verified

Uso

Configure a parte confiável para exigir a verificação do usuário e credenciais detectáveis, e veja a política nas opções e na sessão.
package main

import (
	"fmt"

	"github.com/go-webauthn/webauthn/protocol"
	"github.com/go-webauthn/webauthn/webauthn"
)

type user struct{}

func (user) WebAuthnID() []byte                         { return []byte("user-1") }
func (user) WebAuthnName() string                       { return "user@example.com" }
func (user) WebAuthnDisplayName() string                { return "User" }
func (user) WebAuthnCredentials() []webauthn.Credential { return nil }

func main() {
	w, _ := webauthn.New(&webauthn.Config{
		RPID: "example.com", RPDisplayName: "Example", RPOrigins: []string{"https://example.com"},
		// Without this, options say nothing about UV or discoverable credentials.
		AuthenticatorSelection: protocol.AuthenticatorSelection{
			ResidentKey: protocol.ResidentKeyRequirementRequired, UserVerification: protocol.VerificationRequired,
		},
	})
	creation, session, _ := w.BeginRegistration(user{})
	// The session carries the requirement into FinishRegistration/FinishLogin.
	fmt.Println("uv:", creation.Response.AuthenticatorSelection.UserVerification, session.UserVerification)
	fmt.Println("resident key:", creation.Response.AuthenticatorSelection.ResidentKey)
}

O executor de trechos de código roda cada exemplo literalmente na imagem de contêiner golang:1.27.3-trixie, e a execução falha se a saída não corresponder.

Comando
GOFLAGS=-mod=mod go run .
A saída deve corresponder a (expressão regular)
uv: required required\nresident key: required

Bibliotecas