Porta e cadeado do portão
A senha é a chave da porta. O TOTP é o cadeado do portão da frente: quem só tem a chave da porta ainda fica na rua. Mas se alguém já está dentro da casa (sessão roubada no browser), o cadeado do portão não ajuda.
Um fator não basta
Vazamento de senha é comum; o segundo fator muda a equação para o atacante remoto.
O desenho falha se o “segundo fator” for o mesmo canal (e-mail) que já reseta a senha.
Fatores devem ser *independentes*. E-mail OTP quando a conta de e-mail é o alvo não adiciona muita defesa. SMS falha sob SIM swap. WebAuthn amarra ao dispositivo e ao origin.
MFA fatigue: bombardear push até a vítima aceitar. Prefira número de matching ou TOTP/WebAuthn.
Como isso aparece na prática
Admin do painel
Cenário
Contas admin com senha reutilizada de outro site vazado.
Como o padrão entra
TOTP obrigatório para role admin; backup codes impressos no onboarding.
Trade-off: Mais tickets de “não consigo entrar” — o reset MFA precisa de verificação humana ou identidade forte.
SSO corporativo
Cenário
A empresa já exige MFA no IdP; apps internos não devem pedir outro TOTP.
Como o padrão entra
Confiar no amr/acr do OIDC ou na sessão do IdP; não empilhar MFA duplicado.
Trade-off: Dependência da política do IdP — se alguém enfraquece lá, todos os apps herdam.
Onde isto dá errado
SMS como único 2FA
SIM swap e interceptação de SMS são ataques reais. Use SMS só como fallback, não como padrão.
Sem rate limit no código
Seis dígitos sem bloqueio após N erros viram força bruta. Limite tentativas e a sessão de desafio.
Achar que MFA fecha o produto
IDOR, guards fracos e XSS continuam. MFA protege o login, não a lógica da aplicação.
Login com desafio TOTP
// TOTP (RFC 6238): segredo compartilhado + relogio. O app authenticator
// gera 6 digitos; o servidor verifica com janela de 1 passo (±30s).
import { verifySync } from "otplib";
function checarTotp(secret: string, codigo: string, agora = Date.now()) {
const ok = verifySync({ token: codigo, secret, epoch: agora }).valid;
if (!ok) throw new Error("codigo MFA invalido");
}
// Fluxo: senha OK -> desafio MFA -> so entao emite sessao.
// Backup codes de uso unico para quando o telefone morre.
async function login(email: string, senha: string, totp?: string) {
const user = await usuarios.verificarSenha(email, senha);
if (!user) return { status: 401 as const };
if (user.mfaAtivo) {
if (!totp) return { status: 401 as const, mfaRequired: true };
checarTotp(user.mfaSecret, totp);
}
return { status: 200 as const, sessao: await sessoes.criar(user.id) };
}Quando usar × quando evitar
Use quando
2- Contas de alto valor e painéis admin.
- Quando o IdP já oferece MFA — ative.
Evite quando
2- Como remendo único de segurança da aplicação.
- SMS obrigatório sem alternativa mais forte.
Testar o que ficou
3 armadilhas de MFA / 2FA viram perguntas, com o nome do padrão escondido, misturadas com padrões parecidos.
Onde isto aparece de verdade
Você já usa isto, talvez sem saber o nome.
Google Authenticator / AegisApps TOTP que geram o código de 6 dígitos a partir do segredo compartilhado.WebAuthn / passkeysSegundo fator (ou fator único) baseado em criptografia no dispositivo, resistente a phishing clássico.prompt MFA do IdPNo OAuth/OIDC, o IdP exige o segundo fator antes de devolver o code.
O padrão em uma linha
Sem nome de domínio, sem cerimônia. Só a ideia.
// Senha ok não basta: falta o segundo fator.
if (user.mfaAtivo && !totpOk) return { mfaRequired: true };O que ele cobra
1 salto a mais entre a chamada e o efeito.
- Fricção no login e suporte a “perdi o telefone” (backup codes, reset seguro)
- SMS como fator é frágil (SIM swap); TOTP/WebAuthn exigem onboarding cuidadoso
Não vale se: a conta não tem valor a proteger e o custo de suporte supera o risco — MFA em ferramenta interna descartável pode ser teatro.
Onde isto aparece
Continue por aqui
- AutenticaçãoAutenticação responde *quem você é*: prova de identidade antes de qualquer permissão. Na web, o desenho padrão é sessão no servidor com cookie httpOnly, Secure e SameSite — o token opaco mora fora do alcance do JavaScript da página. Confundir autenticação com autorização, ou guardar a prova de identidade no localStorage, é o caminho mais curto para vazamento e abuso.
- OAuth 2.0OAuth 2.0 é delegação de acesso: um cliente obtém autorização para agir em nome do usuário sem ver a senha dele. O fluxo moderno é Authorization Code com PKCE; o implícito morreu. OIDC acrescenta identidade (id_token) em cima. Inventar “OAuth caseiro” com senha no body de um SPA costuma ser pior que sessão clássica bem feita.
- Autorização (RBAC e guards)Autorização responde *o que você pode fazer* depois de autenticado. RBAC (roles) e guards/middleware — Nest guards, Next middleware, Express — concentram a decisão perto da rota ou do caso de uso. “Tem `req.user`” não é autorização; IDOR e checagem só no front são as falhas clássicas.
- Rate limitingCapacidade é finita, e demanda não pede licença. Limitar a taxa é escolher conscientemente quem é recusado quando a demanda passa do que se aguenta — em vez de deixar a sobrecarga escolher, degradando o serviço para todo mundo ao mesmo tempo.