Chaves de acesso: o que diabos e por quê?

Chaves de acesso: o que diabos e por quê?

Essas coisas chamadas chaves de acesso com certeza estão fazendo as rondas nos dias de hoje. Eles foram a principal atração do W3C TPAC 2022, ganhou apoio em Safari 16, estão encontrando seu caminho macOS e iOS, e estão programados para serem o futuro para gerenciadores de senhas como 1Password. Eles são já suportado no Android e logo chegarão ao Chrome OS e ao Windows em versões futuras.

Os aprimoramentos de segurança do Geeky OS não são exatamente grandes manchetes na comunidade de front-end, mas é lógico que as chaves de acesso serão uma “coisa”. E, considerando como as senhas e os aplicativos de senha afetam a experiência do usuário em coisas como autenticação e processamento de formulários, podemos pelo menos pensar nisso para saber o que está por vir.

Esse é o ponto deste artigo. Eu tenho estudado e experimentado com senhas - e a API WebAuthn sobre a qual elas são construídas - há algum tempo. Deixe-me compartilhar o que aprendi.

Índice

Terminologia

Aqui está a seção obrigatória da terminologia que você vai querer saber enquanto nos aprofundamos. Como a maioria das tecnologias, as chaves de acesso são forjadas com palavreado esotérico e acrônimos que muitas vezes são obstáculos para a compreensão. Vou tentar desmistificar vários para você aqui.

  • Parte Confiante: o servidor no qual você fará a autenticação. Usaremos "servidor" para indicar a terceira parte confiável neste artigo.
  • Cliente: no nosso caso, o navegador da web ou sistema operacional.
  • Autenticador: Dispositivos de software e/ou hardware que permitem a geração e armazenamento de pares de chaves públicas.
  • FIDO: um corpo de padrões abertos que também cria especificações em torno das credenciais FIDO.
  • WebAuthn: o protocolo subjacente para senhas, também conhecido como FIDO2 credencial ou credenciais FIDO de dispositivo único.
  • chaves de acesso: WebAuthn, mas com sincronização em nuvem (também chamada de credenciais FIDO de vários dispositivos, credenciais detectáveis ​​ou credenciais residentes).
  • Criptografia de chave pública: Um par de chaves gerado que inclui uma chave privada e pública. Dependendo do algoritmo, ele deve ser usado para assinatura e verificação ou criptografia e descriptografia. Isso também é conhecido como criptografia assimétrica.
  • RSA: Um acrônimo dos nomes dos criadores, Rivest Shamir e Adel. RSA é uma família mais antiga, mas ainda útil, de criptografia de chave pública baseada na fatoração de números primos.
  • Criptografia de curva elíptica (ECC): Uma nova família de criptografia baseado em curvas elípticas.
  • ES256: Uma chave pública de curva elíptica que usa um algoritmo de assinatura ECDSA (PDF) com SHA256 para hashing.
  • RS256: Como ES256, mas usa RSA com RSASSA-PKCS1-v1.5 e SHA256.

O que são chaves de acesso?

Antes de falarmos especificamente sobre senhas, precisamos falar sobre outro protocolo chamado WebAuthn (também conhecido como FIDO2). As senhas são uma especificação construída sobre o WebAuthn. WebAuthn permite criptografia de chave pública para substituir senhas. Usamos algum tipo de dispositivo de segurança, como uma chave de hardware ou Trusted Platform Module (TPM), para criar chaves privadas e públicas.

A chave pública é para qualquer um usar. A chave privada, no entanto, não pode ser removida do dispositivo que a gerou. Este foi um dos problemas com o WebAuthn; se você perder o dispositivo, perderá o acesso.

O Passkeys resolve isso fornecendo uma sincronização na nuvem de suas credenciais. Em outras palavras, o que você gera em seu computador agora também pode ser usado em seu telefone (embora, confusamente, também existam credenciais de dispositivo único).

Atualmente, no momento da redação deste artigo, apenas iOS, macOS e Android fornecem suporte completo para senhas sincronizadas em nuvem e, mesmo assim, são limitados pelo navegador que está sendo usado. O Google e a Apple fornecem uma interface para sincronização por meio de seus Gerenciador de senhas do GoogleChaveiro Apple iCloud serviços, respectivamente.

Como as senhas substituem as senhas?

Na criptografia de chave pública, você pode executar o que é conhecido como assinatura. A assinatura pega um pedaço de dados e o executa por meio de um algoritmo de assinatura com a chave privada, onde pode ser verificado com a chave pública.

Qualquer pessoa pode gerar um par de chaves públicas e não é atribuível a ninguém, pois qualquer pessoa poderia tê-lo gerado em primeiro lugar. O que o torna útil é que apenas os dados assinados com a chave privada podem ser verificados com a chave pública. Essa é a parte que substitui uma senha — um servidor armazena a chave pública e nós entramos verificando se temos a outra metade (por exemplo, chave privada), assinando um desafio aleatório.

Como benefício adicional, como estamos armazenando as chaves públicas do usuário em um banco de dados, não há mais preocupação com quebras de senha que afetam milhões de usuários. Isso reduz phishing, violações e uma série de outros problemas de segurança que nosso mundo dependente de senha enfrenta atualmente. Se um banco de dados for violado, tudo isso é armazenado nas chaves públicas do usuário, tornando-o praticamente inútil para um invasor.

Chega de e-mails esquecidos e suas senhas associadas! O navegador lembrará quais credenciais você usou para qual site - tudo o que você precisa fazer é dar alguns cliques e fazer login. Você pode fornecer um meio secundário de verificação para usar a chave de acesso, como biometria ou um pin , mas ainda são muito mais rápidas do que as senhas do passado.

Mais sobre criptografia

A criptografia de chave pública envolve ter uma chave privada e uma chave pública (conhecida como par de chaves). As chaves são geradas juntas e têm usos separados. Por exemplo, a chave privada deve ser mantida em segredo e a chave pública é destinada a quem você deseja trocar mensagens.

Quando se trata de criptografar e descriptografar uma mensagem, a chave pública do destinatário é usada para criptografar uma mensagem de forma que apenas a chave privada do destinatário possa descriptografar a mensagem. Em linguagem de segurança, isso é conhecido como “fornecer confidencialidade”. No entanto, isso não fornece prova de que o remetente é quem diz ser, pois qualquer pessoa pode usar uma chave pública para enviar uma mensagem criptografada a alguém.

Existem casos em que precisamos verificar se uma mensagem realmente veio de seu remetente. Nesses casos, usamos assinatura e verificação de assinatura para garantir que o remetente seja quem diz ser (também conhecido como autenticidade). Na chave pública (também chamada assimétrico) criptografia, isso geralmente é feito assinando o hash de uma mensagem, para que apenas a chave pública possa verificá-la corretamente. O hash e a chave privada do remetente produzem uma assinatura depois de executá-la por meio de um algoritmo, e então qualquer pessoa pode verificar se a mensagem veio do remetente com a chave pública do remetente.

Como acessamos as senhas?

Para acessar as senhas, primeiro precisamos gerá-las e armazená-las em algum lugar. Algumas dessas funcionalidades podem ser fornecidas com um autenticador. Um integrado é qualquer dispositivo baseado em hardware ou software que fornece a capacidade de geração de chave criptográfica. Pense naquelas senhas de uso único que você obtém de Google Authenticator1Passwordou LastPass, Entre outros.

Por exemplo, um autenticador de software pode usar o Trusted Platform Module (TPM) ou enclave seguro de um dispositivo para criar credenciais. As credenciais podem ser armazenadas remotamente e sincronizadas entre dispositivos, por exemplo, senhas. Um autenticador de hardware seria algo como um Yubikey, que pode gerar e armazenar chaves no próprio dispositivo.

Para acessar o autenticador, o navegador precisa ter acesso ao hardware e, para isso, precisamos de uma interface. A interface que usamos aqui é o Client to Authenticator Protocol (CTAP). Ele permite o acesso a diferentes autenticadores em diferentes mecanismos. Por exemplo, podemos acessar um autenticador por NFC, USB e Bluetooth utilizando o CTAP.

Uma das maneiras mais interessantes de usar chaves de acesso é conectando seu telefone por Bluetooth a outro dispositivo que pode não oferecer suporte a chaves de acesso. Quando os dispositivos são emparelhados por Bluetooth, posso fazer login no navegador do meu computador usando meu telefone como intermediário!

A diferença entre senhas e WebAuthn

Chaves de acesso e chaves WebAuthn diferem de várias maneiras. Primeiro, as senhas são consideradas credenciais de vários dispositivos e podem ser sincronizadas entre os dispositivos. Por outro lado, as chaves WebAuthn são credenciais de dispositivo único — uma maneira sofisticada de dizer que você está vinculado a um dispositivo para verificação.

Em segundo lugar, para autenticar em um servidor, as chaves WebAuthn precisam fornecer o identificador do usuário para login, após o qual um allowCredentials list é retornado ao cliente do servidor, que informa quais credenciais podem ser usadas para efetuar login. As senhas ignoram esta etapa e usam o nome de domínio do servidor para mostrar quais chaves já estão vinculadas a esse site. Você pode selecionar a chave de acesso associada a esse servidor, pois ela já é conhecida pelo seu sistema.

Caso contrário, as chaves são criptograficamente as mesmas; eles diferem apenas em como são armazenados e quais informações usam para iniciar o processo de login.

O processo… em poucas palavras

O processo para gerar um WebAuthn ou uma chave de acesso é muito semelhante: obtenha um desafio do servidor e use o navigator.credentials.create API da Web para gerar um par de chaves públicas. Em seguida, envie o desafio e a chave pública de volta ao servidor para ser armazenado.

Ao receber a chave pública e o desafio, o servidor valida o desafio e a sessão a partir da qual foi criado. Se isso acontecer, a chave pública é armazenada, bem como qualquer outra informação relevante, como o identificador do usuário ou dados de atestado, no banco de dados.

O usuário tem mais uma etapa — recuperar outro desafio do servidor e usar o navigator.credentials.get API para assinar o desafio. Enviamos de volta o desafio assinado para o servidor, e o servidor verifica o desafio e, em seguida, faz login se a assinatura for aprovada.

Há, é claro, um pouco mais em cada etapa. Mas geralmente é assim que entraríamos em um site usando WebAuthn ou senhas.

A carne e as batatas

As chaves de acesso são utilizadas em duas fases distintas: a atestado e afirmação fases.

A fase de atestado também pode ser considerada como a fase de registro. Você se inscreveria com um e-mail e senha para um novo site, no entanto, neste caso, estaríamos usando nossa chave de acesso.

A fase de afirmação é semelhante a como você faria login em um site após se inscrever.

Atestado

Chaves de acesso: o que diabos e por quê? Inteligência de dados PlatoBlockchain. Pesquisa vertical. Ai.
Ver em tamanho grande

navigator.credentials.create A API é o foco da nossa fase de atestado. Estamos cadastrados como novo usuário no sistema e precisamos gerar um novo par de chaves públicas. No entanto, precisamos especificar que tipo de par de chaves queremos gerar. Isso significa que precisamos fornecer opções para navigator.credentials.create.

// The `challenge` is random and has to come from the server
const publicKey: PublicKeyCredentialCreationOptions = { challenge: safeEncode(challenge), rp: { id: window.location.host, name: document.title, }, user: { id: new TextEncoder().encode(crypto.randomUUID()), // Why not make it random? name: 'Your username', displayName: 'Display name in browser', }, pubKeyCredParams: [ { type: 'public-key', alg: -7, // ES256 }, { type: 'public-key', alg: -256, // RS256 }, ], authenticatorSelection: { userVerification: 'preferred', // Do you want to use biometrics or a pin? residentKey: 'required', // Create a resident key e.g. passkey }, attestation: 'indirect', // indirect, direct, or none timeout: 60_000,
};
const pubKeyCredential: PublicKeyCredential = await navigator.credentials.create({ publicKey
});
const { id // the key id a.k.a. kid
} = pubKeyCredential;
const pubKey = pubKeyCredential.response.getPublicKey();
const { clientDataJSON, attestationObject } = pubKeyCredential.response;
const { type, challenge, origin } = JSON.parse(new TextDecoder().decode(clientDataJSON));
// Send data off to the server for registration

Nós conseguiremos PublicKeyCredential que contém um AuthenticatorAttestationResponse que volta após a criação. A credencial tem o ID do par de chaves gerado.

A resposta fornece algumas informações úteis. Primeiro, temos nossa chave pública nesta resposta e precisamos enviá-la ao servidor para ser armazenada. Em segundo lugar, também recebemos de volta o clientDataJSON propriedade que podemos decodificar e, a partir daí, recuperar o typechallengeorigin da chave de acesso.

Para atestado, queremos validar o typechallengeorigin no servidor, bem como armazenar a chave pública com seu identificador, por exemplo, kid. Também podemos, opcionalmente, armazenar o attestationObject se quisermos. Outra propriedade útil para armazenar é o COSE algoritmo, que é definido acima em nosso  PublicKeyCredentialCreationOptions de alg: -7 or alg: -256, para verificar facilmente quaisquer contestações assinadas na fase de asserção.

afirmação

Chaves de acesso: o que diabos e por quê? Inteligência de dados PlatoBlockchain. Pesquisa vertical. Ai.
Ver em tamanho grande

navigator.credentials.get A API será o foco da fase de asserção. Conceitualmente, seria onde o usuário efetua login no aplicativo da web após se inscrever.

// The `challenge` is random and has to come from the server
const publicKey: PublicKeyCredentialRequestOptions = { challenge: new TextEncoder().encode(challenge), rpId: window.location.host, timeout: 60_000,
};
const publicKeyCredential: PublicKeyCredential = await navigator.credentials.get({ publicKey, mediation: 'optional',
});
const { id // the key id, aka kid
} = pubKeyCredential;
const { clientDataJSON, attestationObject, signature, userHandle } = pubKeyCredential.response;
const { type, challenge, origin } = JSON.parse(new TextDecoder().decode(clientDataJSON));
// Send data off to the server for verification

Nós vamos novamente obter um PublicKeyCredential com um AuthenticatorAssertionResponse desta vez. A credencial inclui novamente o identificador de chave.

Também obtemos o typechallengeorigin do clientDataJSON novamente. O signature agora está incluído na resposta, bem como o authenticatorData. Vamos precisar deles e do clientDataJSON para verificar se foi assinado com a chave privada.

authenticatorData inclui algumas propriedades que valem a pena rastrear Primeiro é o hash SHA256 da origem que você está usando, localizado nos primeiros 32 bytes, o que é útil para verificar se a solicitação vem do mesmo servidor de origem. Segundo é o signCount, que vai do byte 33 ao 37. Isso é gerado a partir do autenticador e deve ser comparado ao seu valor anterior para garantir que nada suspeito esteja acontecendo com a chave. O valor sempre deve ser 0 quando for uma chave de acesso de vários dispositivos e deve ser aleatoriamente maior que o signCount anterior quando for uma chave de acesso de um único dispositivo.

Depois de confirmar seu login, você deve estar conectado - parabéns! Chaves de acesso é um protocolo muito bom, mas vem com algumas ressalvas.

Algumas desvantagens

Há muitas vantagens no Passkeys, no entanto, existem alguns problemas com ele no momento em que este livro foi escrito. Por um lado, as chaves de acesso ainda são um pouco precoces em termos de suporte, com apenas credenciais de dispositivo único permitidas no Windows e muito pouco suporte para sistemas Linux. Senhas.dev fornece uma boa mesa que é como o Canius deste protocolo.

Além disso, as plataformas de chaves de acesso do Google e da Apple não se comunicam entre si. Se você deseja obter suas credenciais do seu telefone Android para o seu iPhone ... bem, você está sem sorte por enquanto. Isso não quer dizer que não haja interoperabilidade! Você pode fazer login no seu computador usando o telefone como um autenticador. Mas seria muito mais limpo apenas tê-lo integrado ao sistema operacional e sincronizado sem ser bloqueado no nível do fornecedor.

Para onde vão as coisas?

Como será o protocolo de senhas do futuro? Parece muito bom! Uma vez que ele ganha suporte de mais sistemas operacionais, deve haver uma absorção no uso, e você começará a vê-lo sendo usado cada vez mais na natureza. Alguns gerenciadores de senhas vão mesmo apoiá-los em primeira mão.

As chaves de acesso não são suportadas apenas na web. Android e iOS ambos suportarão senhas nativas como cidadãos de primeira classe. Ainda estamos nos primeiros dias de tudo isso, mas esperamos vê-lo mencionado cada vez mais.

Afinal, eliminamos a necessidade de senhas e, com isso, tornamos o mundo mais seguro para isso!

Recursos

Aqui estão mais alguns recursos se você quiser aprender mais sobre chaves de acesso. Há também um repositório e uma demonstração que montei para este artigo.

Carimbo de hora:

Mais de Truques CSS