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:
usernamepara o identificador do login, mesmo quando ele é um e-mail;current-password;new-password;one-time-codepara códigos de verificação. - Pessoa:
name, ougiven-nameefamily-namese você separa nome e sobrenome;email;tel;bday. - Endereço:
postal-code,street-address(ouaddress-line1eaddress-line2),address-level2para a cidade,address-level1para 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
- Login: identificador com
usernamee senha comcurrent-password, dentro de umformcom botão de envio. - Cadastro: identificador com
usernamee senha comnew-password. Se pedir confirmação, os dois campos levamnew-password. - Troca de senha: senha atual com
current-password, nova comnew-password, e um campo com o usuário (pode ser somente leitura) comusername, para o gerenciador saber qual conta atualizar. - 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. - Código por SMS ou e-mail: um único campo com
one-time-codeeinputmode="numeric", em vez de seis caixinhas. - 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-passwordno 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.
maxlengthpequeno 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
usernameecurrent-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?
Referência: https://developer.mozilla.org/docs/Web/HTML/Attributes/autocomplete