Programação Por Equipe DevBras

Capa do artigo: Autocomplete certo no login e no cadastro: o gerenciador de senha agradece

Autocomplete certo no login e no cadastro: o gerenciador de senha agradece

Use os tokens de autocomplete certos em login, cadastro, troca de senha, código por SMS e endereço, pare de bloquear colar e veja por que autocomplete="off" não protege ninguém.

O gerenciador de senhas oferece a credencial salva e o campo de senha não aceita. A pessoa tenta colar e o site bloqueia o colar. Ela digita de memória, erra duas vezes e vai para "esqueci a senha". O time de produto acha que o login está seguro. Na prática, ele está empurrando o cliente para senhas curtas e repetidas.

A resposta curta: marque cada campo com o token de autocomplete certo. No login, username e current-password. No cadastro e na troca de senha, new-password, para o gerenciador sugerir uma senha forte. Em dados pessoais, os tokens padronizados como name, email, tel e postal-code. E não use autocomplete="off" nem bloqueie colar no campo de senha.

Por que o navegador precisa da dica

O navegador e o gerenciador de senhas tentam adivinhar o que cada campo pede olhando type, name, id e o texto próximo. Adivinhação erra: um campo name="login" pode ser e-mail, CPF ou matrícula, e um formulário com dois campos de senha pode ser cadastro ou troca de senha. O atributo autocomplete tira a dúvida com um vocabulário padronizado pela especificação do HTML.

A diferença entre current-password e new-password é a mais importante. Com a primeira, o gerenciador preenche a senha salva. Com a segunda, ele oferece gerar uma senha nova e forte e salva o resultado. Trocar uma pela outra faz o gerenciador sugerir senha nova no login ou preencher a senha antiga no cadastro.

Os tokens que você mais vai usar

  • Identidade da conta: username para o identificador do login, mesmo quando ele é um e-mail; current-password; new-password; one-time-code para códigos de verificação.
  • Pessoa: name, ou given-name e family-name se você separa nome e sobrenome; email; tel; bday.
  • Endereço: postal-code, street-address (ou address-line1 e address-line2), address-level2 para a cidade, address-level1 para o estado, country.
  • Empresa: organization.
  • Cartão: cc-name, cc-number, cc-exp, cc-csc, quando o formulário é seu. Se o pagamento é feito num campo hospedado pelo provedor, quem marca é ele.

Para endereço de entrega e de cobrança no mesmo formulário, prefixe com shipping ou billing, como shipping postal-code. CPF e CNPJ não têm token próprio. Deixe esses campos sem autocomplete e com inputmode="numeric".

Como marcar cada formulário

  1. Login: identificador com username e senha com current-password, dentro de um form com botão de envio.
  2. Cadastro: identificador com username e senha com new-password. Se pedir confirmação, os dois campos levam new-password.
  3. Troca de senha: senha atual com current-password, nova com new-password, e um campo com o usuário (pode ser somente leitura) com username, para o gerenciador saber qual conta atualizar.
  4. Login em duas etapas (e-mail numa tela, senha na outra): na segunda tela, mantenha o identificador presente com username, para o gerenciador associar a senha à conta certa.
  5. Código por SMS ou e-mail: um único campo com one-time-code e inputmode="numeric", em vez de seis caixinhas.
  6. Endereço: tokens de endereço em cada campo, com o CEP primeiro se você completa o resto por consulta.
<form method="post" action="/entrar">
  <label for="usuario">E-mail</label>
  <input id="usuario" name="email" type="email" autocomplete="username" required>

  <label for="senha">Senha</label>
  <input id="senha" name="senha" type="password" autocomplete="current-password" required>

  <button type="submit">Entrar</button>
</form>
<form method="post" action="/conta/senha">
  <label for="conta">Conta</label>
  <input id="conta" name="conta" autocomplete="username" value="ana@exemplo.com.br" readonly>

  <label for="senha-atual">Senha atual</label>
  <input id="senha-atual" name="senha_atual" type="password" autocomplete="current-password">

  <label for="senha-nova">Nova senha</label>
  <input id="senha-nova" name="senha_nova" type="password" autocomplete="new-password" minlength="12">

  <button type="submit">Trocar senha</button>
</form>

Para o código de verificação:

<label for="codigo">Código enviado por SMS</label>
<input id="codigo" name="codigo" autocomplete="one-time-code" inputmode="numeric">

Se você oferece passkeys, o token webauthn pode ser combinado com username no campo de identificador, para o navegador sugerir a passkey ali mesmo. Isso depende da implementação de WebAuthn no servidor, então só acrescente quando ela existir.

Por que autocomplete="off" não protege

O argumento costuma ser "não queremos que a senha fique gravada no computador". Mas o computador é da pessoa, e a decisão de salvar ou não é dela. Além disso, muitos navegadores e gerenciadores ignoram autocomplete="off" em campos de login justamente porque isso prejudica a segurança de quem usa. O resultado prático do atributo é o site parecer quebrado em alguns navegadores e funcionar em outros.

Bloquear colar é pior ainda. Quem usa gerenciador e não consegue colar acaba escolhendo uma senha que consiga digitar, ou seja, curta e memorizável. As recomendações do NIST para autenticação digital pedem que se permita colar no campo de senha. A proteção real está do lado do servidor: senha guardada com hash forte, como mostra login com senha protegida, e limite de tentativas, como em limite de tentativa que avisa.

Um detalhe que quebra gerenciadores silenciosamente: maxlength pequeno no campo de senha. O gerenciador gera 20 caracteres, o campo corta em 12 sem avisar, e a senha salva no gerenciador não é a que o servidor recebeu. No próximo login, nada funciona. Se precisar de limite, que seja generoso, e igual no cadastro, no login e no servidor.

Como testar

Use um gerenciador de senhas de verdade, o do navegador ou um externo. Crie uma conta de teste pelo cadastro e confirme que ele ofereceu gerar a senha e salvou. Saia, volte ao login e confira se ele preenche de primeira. Troque a senha e veja se ele atualiza a credencial existente em vez de criar uma segunda. No celular, peça um código por SMS e confira se o teclado sugere o código. A estrutura visual do login, com rótulos e mostrar senha, está em formulário de login legível.

Erros comuns

  • new-password no login. O gerenciador sugere uma senha nova em vez de preencher a salva, e a pessoa fica confusa.
  • autocomplete="off" no login. Alguns navegadores obedecem e outros não, e quem obedece empurra a pessoa para senha fraca.
  • Bloquear colar no campo de senha. Gerenciadores deixam de funcionar e a pessoa escolhe uma senha que caiba na memória.
  • maxlength pequeno na senha. A senha gerada é cortada sem aviso e o próximo login falha sem explicação.
  • Troca de senha sem campo de usuário. O gerenciador não sabe qual conta atualizar e cria uma credencial solta.
  • Seis caixinhas para o código. O preenchimento automático do código não funciona e colar só preenche a primeira.

Checklist

  • O login usa username e current-password.
  • Cadastro e troca de senha usam new-password.
  • A troca de senha tem um campo com o usuário marcado com username.
  • Nenhum campo de login tem autocomplete="off" nem bloqueio de colar.
  • O limite de tamanho da senha é generoso e igual em todas as telas e no servidor.
  • Código de verificação usa um campo só, com one-time-code.
  • Campos de nome, e-mail, telefone e endereço têm os tokens padronizados.
  • O fluxo completo foi testado com um gerenciador de senhas real.

Abra o login do seu sistema numa janela anônima com o gerenciador de senhas ativo. Ele reconhece os campos e preenche a credencial de primeira, sem você clicar em nada além da sugestão?

Avalie este artigo

Referência: https://developer.mozilla.org/docs/Web/HTML/Attributes/autocomplete