Projetando um back-end de recuperação de conta mais seguro para aplicativos de consumo


Um comprador descobre um pedido desconhecido, redefine sua senha e presume que sua conta está segura. Dez minutos depois, o usuário não autorizado altera novamente o endereço de entrega.

A redefinição de senha funcionou. O sistema de recuperação falhou.

Para os desenvolvedores que criam aplicativos de consumo, a recuperação precisa de uma definição mais forte de sucesso: o cliente legítimo recupera o acesso, o acesso não autorizado termina e o cliente pode entender o que permanece sem solução.

Este artigo desenvolve um design de back-end usando exemplos de Node.js e PostgreSQL. Os trechos ilustram controles individuais em vez de uma implementação completa de autenticação.

Defina invariantes de segurança antes dos endpoints

Comece com propriedades que devem permanecer verdadeiras independentemente de novas tentativas, solicitações simultâneas ou falhas de serviço:

  • Um token de recuperação autoriza apenas a operação pretendida.
  • Um token pode ser consumido no máximo uma vez.
  • Uma sessão de recuperação não pode fazer pedidos ou exportar dados da conta.
  • A conclusão da recuperação comprometida invalida sessões autenticadas anteriormente.
  • As ações de recuperação permanecem vinculadas à conta do cliente verificado.

Essas propriedades fornecem melhor orientação de design do que uma lista de telas. Eles também se tornam critérios de aceitação testáveis.

Considere as consequências para o consumidor de cada falha. Tokens reutilizáveis ​​podem permitir que um invasor recupere o acesso. Sessões de recuperação irrestritas podem expor o histórico de pedidos. A revogação incompleta pode fazer com que o comprador compartilhe o controle com o invasor.

Separe senhas esquecidas de suspeitas de comprometimento

Uma solicitação de senha esquecida e um relatório de conta comprometida não devem acionar fluxos de trabalho idênticos.

Para recuperação comum de senha, um canal de e-mail previamente estabelecido pode ser um fator de verificação apropriado. Durante a suspeita de comprometimento, essa caixa de correio ou os detalhes de recuperação da conta também podem ser comprometidos.

O Folha de referências de senha esquecida do OWASP recomenda tokens seguros, com vencimento e de uso único e respostas consistentes de descoberta de conta. Sua orientação de recuperação de comprometimento também enfatiza a revisão dos métodos de autenticação e detalhes de recuperação e, em seguida, invalida as sessões existentes e as credenciais de recuperação pendentes.

Não congele uma conta apenas porque uma pessoa não autenticada envia uma solicitação de recuperação. Caso contrário, os invasores poderão transformar o endpoint de relatório em um mecanismo de negação de serviço.

Torne explícita a sua política de avaliação e verificação de riscos. Um token enviado para um endereço de e-mail demonstra acesso a esse canal; não estabelece de forma independente a identidade da pessoa no mundo real.

Gere tokens com entropia suficiente

Para um token de recuperação opaco, use um gerador aleatório criptograficamente seguro:

import { randomBytes, createHash } from "node:crypto";

const digest = value =>
  createHash("sha256").update(value, "utf8").digest("hex");

const token = randomBytes(32).toString("base64url");
const tokenHash = digest(token);



Os 32 bytes aleatórios fornecem 256 bits de entropia antes da codificação. Armazene o resumo em vez do token de acesso para que uma leitura do banco de dados não revele imediatamente credenciais de recuperação utilizáveis.

Esta escolha de hash se aplica a tokens aleatórios de alta entropia. As senhas selecionadas por humanos precisam de um esquema de hash de senha dedicado; não reutilize esta função para armazenamento de senha.

Escolha a expiração com base no seu fluxo de trabalho. Quinze minutos podem ser adequados para um aplicativo, enquanto outro precisa de uma janela diferente. Indique o prazo claramente e simplifique a solicitação de outro link.

Use uma origem fixa e confiável ao construir URLs de recuperação. Não os construa a partir de um cabeçalho de host de solicitação não validado.

Mantenha as páginas com tokens livres de scripts desnecessários de terceiros. Edite segredos dos logs de solicitação, use uma política de referência apropriada e troque um token validado por uma sessão limitada antes de navegar para outras páginas.

Consumir o token atomicamente

Uma implementação comum verifica um token, atualiza credenciais e marca o token como usado.

Duas solicitações simultâneas podem passar na verificação.

Use uma mutação condicional do banco de dados:

UPDATE recovery_tokens
SET consumed_at = CURRENT_TIMESTAMP
WHERE token_hash = $1
  AND purpose = 'account_recovery'
  AND consumed_at IS NULL
  AND expires_at > CURRENT_TIMESTAMP
RETURNING account_id;

Somente uma solicitação que receba uma linha retornada poderá continuar.

Aplique uma restrição UNIQUE em token_hash para que um token identifique exatamente um registro. Este exemplo assume o isolamento de leitura confirmada padrão do PostgreSQL; um isolamento mais rigoroso pode exigir o tratamento de falhas de serialização.

A reivindicação do token e a criação da sessão de recuperação local resultante devem acontecer dentro de uma transação de banco de dados. Se a criação da sessão falhar, reverta a reclamação para que o cliente não fique com um token consumido e sem saída.

PostgreSQL documenta o comportamento de ATUALIZAÇÃO e RETORNOjuntamente com isolamento de transação. Entenda como seu banco de dados real lida com mutações simultâneas antes de adotar esse padrão.

Parametrize a consulta, restrinja o comprimento da entrada do token e aplique controles de abuso antes de trabalhos caros.

Abrir um link com GET não deve concluir a recuperação ou alterar as credenciais. Os scanners de segurança de e-mail podem visitar links automaticamente. Exija uma solicitação de alteração de estado explícita e protegida.

Dê às sessões de recuperação uma política de autorização separada

Uma sessão de recuperação deve ser distinguível de uma sessão normal de compras.

type RecoveryAction =
  | "review_security"
  | "replace_credentials"
  | "submit_order_dispute";

function requireRecoveryAction(
  session: RecoverySession,
  action: RecoveryAction,
  now: number
) {
  if (
    session.kind !== "recovery" ||
    session.expiresAt <= now ||
    !session.allowedActions.includes(action)
  ) {
    throw new ForbiddenError();
  }
}

Este exemplo pressupõe que o código do servidor confiável já autenticou e carregou a sessão. Nunca aceite um ID de conta ou matriz de permissões do navegador como oficial.

Use listas de permissões explícitas em middleware. Um endpoint de checkout normal deve rejeitar sessões de recuperação mesmo que contenham um identificador de conta válido.

Verifique a propriedade dos recursos separadamente. Uma solicitação de disputa de pedido precisa de permissão para enviar uma disputa e de confirmação de que o pedido pertence à conta verificada.

Para sessões de recuperação baseadas em cookies, configure HttpOnly, Secure e uma política SameSite apropriada. Proteja solicitações de mudança de estado contra CSRF; sinalizadores de cookies por si só não são um design de autorização completo.

Tornar a revogação executável em todas as solicitações

Uma alteração de senha não invalida automaticamente os tokens de acesso assinados.

Um design armazena uma versão de segurança na conta e copia essa versão em cada sessão normal:

account.security_version = 12
session.security_version = 12

Durante a finalização, incremente a versão da conta. As solicitações subsequentes rejeitam sessões cuja versão não corresponde mais.

Esse design funciona somente se as solicitações protegidas verificarem o estado atual do servidor. Um cache obsoleto pode estender o acesso do invasor. Defina a invalidação do cache e o comportamento de propagação e documente qualquer atraso de revogação restante.

Para obter uma consistência mais forte, serialize as mutações sensíveis à segurança na linha da conta. Uma solicitação autorizada imediatamente antes da revogação não deve confirmar uma alteração de credencial ou endereço posteriormente sem verificar a versão atual.

Revise também tokens de atualização, dispositivos lembrados, links de redefinição pendentes e métodos de autenticação não autorizados. A revogação de um cookie não cobre todos os caminhos de volta à conta.

O Folha de dicas de gerenciamento de sessão OWASP fornece uma base para o raciocínio sobre o tempo de vida e a invalidação da sessão.

Lidar com falhas parciais sem enganar o cliente

Um fluxo de trabalho de recuperação pode envolver um provedor de identidade, um banco de dados de aplicativos, um serviço de e-mail e um sistema de pedidos.

Evite exibir “Sua conta está segura” imediatamente após a primeira operação bem-sucedida.

Persista um caso de recuperação com estágios explícitos, como verificado, protegido e concluído. Registre quais operações necessárias foram bem-sucedidas e quais permanecem pendentes.

Quando for necessário trabalho em segundo plano, use um registro de caixa de saída confirmado juntamente com a mudança de estado local. Os trabalhadores podem tentar novamente operações externas, desde que essas operações sejam idempotentes ou tenham tratamento duplicado.

Mantenha os recursos confidenciais restritos até que as operações de segurança necessárias sejam concluídas. Informe ao cliente quando a restauração do acesso estiver pendente, forneça uma referência do caso e explique como obter ajuda.

Uma falha de notificação é diferente de uma falha de revogação de sessão. Defina quais falhas bloqueiam a conclusão em vez de tratar todas as tarefas como igualmente críticas.

Projete o front-end em torno do estado preciso do back-end

O navegador deve exibir o status de recuperação do servidor, e não inferir a conclusão de um envio de formulário bem-sucedido.

Use rótulos de campo visíveis, erros acionáveis ​​e mensagens claras de progresso. A validação do lado do cliente melhora a usabilidade, mas todos os requisitos também devem ser verificados no servidor.

SitePoints guia para formulários HTML e validação de restrições é um pano de fundo útil para a camada de interface.

Após a restauração do acesso à conta, ofereça orientações adequadas à situação do consumidor. Usuários dos EUA podem consultar IdentidadeTheft.gov para assistência mais ampla contra roubo de identidade. Consumidores avaliando pago recuperação de identidade o apoio deve rever o seu âmbito, elegibilidade e termos.

Mantenha essa assistência externa separada das responsabilidades da própria aplicação. Um recurso opcional não deve tornar-se um pré-requisito para garantir uma conta de compras.

Para proteção futura, explore métodos de autenticação mais fortes. SitePoints Guia do desenvolvedor para implementação de chaves de acesso oferece uma introdução. Revise a segurança alternativa juntamente com qualquer atualização de autenticação.

Teste os caminhos de falha com infraestrutura real

Use testes de integração para verificar o comportamento do banco de dados e da sessão. Uma simulação não pode demonstrar que duas solicitações SQL competem com segurança pelo mesmo token.

Teste Resultado necessário
Envie o mesmo token simultaneamente Exatamente uma sessão de recuperação é criada
Falha na criação da sessão após reivindicação do token A transação é revertida
Use uma sessão de recuperação na finalização da compra A autorização rejeita a solicitação
Apresentar uma sessão anterior após a finalização O acesso protegido foi rejeitado
Envie um ID de pedido de outra conta A validação de propriedade rejeita
Tentar novamente uma tarefa de recuperação em segundo plano Nenhuma alteração de segurança duplicada ocorre
Falha em uma etapa de revogação externa obrigatória O caso permanece incompleto

Use contas e pedidos sintéticos. Capture evidências do comportamento em teste sem registrar segredos de recuperação.

O melhor endpoint de recuperação não é apenas aquele que retorna uma resposta bem-sucedida. É aquele cujas transições de estado permanecem seguras quando as solicitações se sobrepõem, os trabalhadores tentam novamente e os serviços downstream falham – e cujo status faz sentido para o cliente que espera para recuperar o controle.



Source link