Análise detalhada de userverification

Este documento discute o que é userVerification no WebAuthn e os comportamentos do navegador que resultam quando userVerification é especificado durante a criação ou autenticação de chaves de acesso.

As chaves de acesso são criadas com base na criptografia de chave pública. Ao criar uma chave de acesso, um par de chaves pública e privada é gerado, a chave privada é armazenada pelo provedor de chave de acesso e a chave pública é retornada ao servidor da parte confiável (RP) para armazenamento. O servidor pode autenticar um usuário verificando uma assinatura assinada pela mesma chave de acesso usando a chave pública pareada. A flag "user present" (UP) em uma credencial de chave pública prova que alguém interagiu com o dispositivo durante a autenticação.

A verificação do usuário é uma camada opcional de segurança que busca garantir que a pessoa certa estava presente durante a autenticação, e não apenas alguém, como a presença do usuário. Em smartphones, isso geralmente é feito usando o mecanismo de bloqueio de tela, seja biométrico, PIN ou senha. A verificação do usuário foi realizada e é informada na flag "UV" que é retornada nos dados do autenticador durante o registro e a autenticação da chave de acesso.

Captura de tela de uma caixa de diálogo de verificação do usuário no iCloud Keychain no macOS. A caixa de diálogo solicita que o usuário faça login usando o Touch ID, mostrando a origem que solicita a autenticação e o nome de usuário. No canto superior direito da caixa de diálogo, há um botão chamado "Cancelar".
Caixa de diálogo de verificação do usuário nas Chaves do iCloud no macOS.
Captura de tela de uma caixa de diálogo de verificação do usuário no Chrome para Android. A caixa de diálogo solicita que o usuário verifique a identidade usando o reconhecimento facial ou a detecção de impressão digital e mostra a origem que está solicitando a autenticação. No canto inferior esquerdo, há uma opção para verificar usando um PIN.
Caixa de diálogo de verificação do usuário no Chrome para Android.

Como UP e UV são validados no servidor

As flags booleanas de presença do usuário (UP) e de usuário verificado (UV) são sinalizadas para o servidor no campo de dados do autenticador. Durante a autenticação, o conteúdo do campo de dados do autenticador pode ser validado verificando a assinatura usando a chave pública armazenada. Contanto que a assinatura seja válida, o servidor pode considerar as flags como genuínas.

Uma representação da estrutura de dados de autenticação. Da esquerda para a direita, cada seção da estrutura de dados lê "RP ID HASH" (32 bytes), "FLAGS" (1 byte), "COUNTER" (4 bytes, uint32 big-endian) e "ATTESE CRED". DATA (comprimento variável, se presente) e EXTENSIONS (comprimento variável, se presente (CBOR)). A seção "FLAGS" é expandida para mostrar uma lista de flags em potencial, identificadas da esquerda para a direita: "ED", "AT", "0", "BS", "BE", "UV", "0" e "UP".
Campos de dados do autenticador em uma credencial de chave pública.

No registro e na autenticação da chave de acesso, o servidor precisa examinar se a flag UP é true e se a flag UV é true ou false, dependendo do requisito.

Como especificar o parâmetro userVerification

De acordo com a especificação da WebAuthn, o RP pode solicitar uma verificação do usuário com um parâmetro userVerification na criação e na declaração de credenciais. Ele aceita 'preferred', 'required' ou 'discouraged', que significam respectivamente:

  • 'preferred' (padrão): é recomendável usar um método de verificação do usuário no dispositivo, mas ele pode ser ignorado se não estiver disponível. A credencial de resposta contém um valor de sinalização UV de true se a verificação do usuário foi realizada e false se a UV não foi realizada.
  • 'required': é necessário invocar um método de verificação de usuário disponível no dispositivo. Se nenhuma estiver disponível, a solicitação falhará localmente. Isso significa que a credencial de resposta sempre retorna com a flag UV definida como true.
  • 'discouraged': não é recomendável usar um método de verificação do usuário. No entanto, dependendo do dispositivo, a verificação do usuário pode ser realizada de qualquer maneira, e a flag UV pode conter true ou false.

Exemplo de código para a criação de chaves de acesso:

const publicKeyCredentialCreationOptions = {
 
// ...
  authenticatorSelection
: {
    authenticatorAttachment
: 'platform',
    residentKey
: 'required',
    requireResidentKey
: true,
    userVerification
: 'preferred'
 
}
};

const credential = await navigator.credentials.create({
  publicKey
: publicKeyCredentialCreationOptions
});

Exemplo de código para autenticação de chave de acesso:

const publicKeyCredentialRequestOptions = {
  challenge
: /* Omitted challenge data... */,
  rpId
: 'example.com',
  userVerification
: 'preferred'
};

const credential = await navigator.credentials.get({
  publicKey
: publicKeyCredentialRequestOptions
});

Qual opção você deve escolher para userVerification?

O valor de userVerification que você vai usar depende dos requisitos do aplicativo e das necessidades de experiência do usuário.

Quando usar userVerification='preferred'

Use userVerification='preferred' se a experiência do usuário for mais importante que a proteção.

Há ambientes em que a verificação do usuário é mais um obstáculo do que uma proteção. Por exemplo, no macOS onde o Touch ID não está disponível (porque o dispositivo não é compatível, está desativado ou o dispositivo está no modo clamshell), o usuário é solicitado a inserir a senha do sistema. Isso causa atrito, e o usuário pode abandonar a autenticação completamente. Se a eliminação de atrito for mais importante para você, use userVerification='preferred'.

Captura de tela de uma caixa de diálogo de chave de acesso no macOS que aparece quando o Touch ID não está disponível. A caixa de diálogo contém informações como a origem que solicita a autenticação e o nome de usuário. No canto superior direito da caixa de diálogo, há um botão chamado "Cancelar".
Uma caixa de diálogo de chave de acesso exibida no macOS quando o Touch ID não está disponível.

Com userVerification='preferred', a flag de UV é true se a verificação do usuário for realizada e false se a verificação do usuário for ignorada. Por exemplo, no macOS, onde o Touch ID não está disponível, o usuário precisa clicar em um botão para pular a verificação, e a credencial de chave pública inclui uma flag UV false.

A flag UV pode ser um indicador na sua análise de risco. Se a tentativa de login parecer arriscada devido a outros fatores, você pode apresentar outros desafios de login ao usuário se a verificação não tiver sido realizada.

Quando usar userVerification='required'

Use userVerification='required' se você achar que UP e UV são absolutamente necessários.

A desvantagem dessa opção é que o usuário pode ter mais dificuldade para fazer login. Por exemplo, no macOS, onde o Touch ID não está disponível, o usuário precisa digitar a senha do sistema.

Com userVerification='required', é possível garantir que a verificação do usuário seja realizada no dispositivo. Verifique se o servidor verifica se a flag UV é true.

Conclusão

Ao aproveitar a verificação do usuário, as partes que dependem de chaves de acesso podem avaliar a probabilidade de o proprietário do dispositivo fazer login. A decisão de exigir a verificação do usuário ou torná-la opcional depende de quão crítico o mecanismo de fallback de login é para o fluxo do usuário. Verifique se o servidor verifica as flags UP e UV para a autenticação de usuário da chave de acesso.