7 pontos por GN⁺ 2024-10-11 | 1 comentários | Compartilhar no WhatsApp
  • Um guia básico de referência para projetar a implementação de autenticação em aplicações web, com o objetivo de preencher lacunas nos materiais online sobre autenticação
  • Material gratuito e de código aberto, oferecido com manutenção da comunidade
  • Parte do conteúdo pode refletir opiniões ou estar incompleta, por isso é mais adequado usá-lo como material de apoio do que como critério único
  • Recomenda-se usá-lo junto com a OWASP Cheat Sheet Series, um material de referência sobre segurança de autenticação
  • É possível abrir uma nova issue para enviar sugestões ou preocupações e participar da melhoria da documentação

Objetivo e natureza do documento

  • The Copenhagen Book fornece diretrizes gerais que podem servir de referência ao implementar autenticação (auth) em aplicações web
  • Seu modelo de operação é o seguinte
    • É oferecido gratuitamente
    • É de código aberto
    • É mantido pela comunidade
  • O conteúdo pode, às vezes, refletir opiniões ou não estar completo

Materiais complementares e como participar

  • Ao implementar autenticação, recomenda-se consultá-lo junto com a OWASP Cheat Sheet Series
  • Se houver sugestões ou preocupações, é possível abrir uma nova issue

1 comentários

 
GN⁺ 2024-10-11
Opiniões do Hacker News
  • Se não me engano, este texto parece ter sido escrito pelo autor da Lucia, uma biblioteca popular de autenticação para TypeScript
    Recentemente, ele anunciou que não vê mais a biblioteca Lucia como uma forma ergonômica de implementar autenticação, e que vai descontinuar a biblioteca e substituí-la por uma série de guias em texto
    A prévia inicial dos guias era agradável de ler e também combinava bem com The Copenhagen Book
    https://github.com/lucia-auth/lucia
    https://github.com/lucia-auth/lucia/discussions/1707
    https://lucia-next.pages.dev/

    • Eu estava curioso para saber se ele tinha escrito por que chegou a essa conclusão, e estava aqui: https://github.com/lucia-auth/lucia/discussions/1707
      É raro ver alguém perceber sinais de que a complexidade estava prestes a explodir, admitir que a biblioteca já não era mais útil nem para si mesmo, e sair humildemente do caminho padrão da comum inchação de bibliotecas
    • Ainda assim, é bem provável que Lucia seja rapidamente substituída por outra biblioteca de autenticação popular
      Na prática, 99% das pessoas só precisam de login/logout, e isso é extremamente útil quando fornecido como biblioteca
      Se você precisa oferecer passkeys Web 8.0 por sockets de curva elíptica em WASM, talvez faça sentido criar por conta própria ou usar Auth0, mas é estranho jogar a especificação do OAuth e uma lista de armadilhas para alguém que está fazendo um app CRUD de receitas e mandar essa pessoa implementar autenticação sozinha
      Essa pessoa deveria se concentrar na ideia real em vez de reinventar a infraestrutura básica, e muita gente acabaria implementando errado, ficando na prática sem autenticação
  • Esta parte está errada: “endereços de e-mail não diferenciam maiúsculas de minúsculas”
    https://thecopenhagenbook.com/email-verification
    Segundo o padrão de e-mail, endereços de e-mail diferenciam maiúsculas de minúsculas
    Se você transformar um e-mail em minúsculas durante o envio, a mensagem pode ir para a pessoa errada, o que é perigoso em autenticação
    Muitos provedores de e-mail conhecidos escolhem não diferenciar maiúsculas de minúsculas, mas um site que lida com autenticação genérica deveria recomendar o caso geral
    https://stackoverflow.com/questions/9807909/are-email-addres...
    Além disso, nem sempre é claro qual é a forma oposta de caixa de um caractere, e isso também pode mudar com o tempo. Por exemplo, o ß maiúsculo do alemão foi adicionado ao Unicode em 2008, então, em programação geral, é melhor evitar diferenciação de maiúsculas/minúsculas sempre que possível

    • A resposta mais votada do Stack Overflow que você linkou diz justamente o contrário: “na prática, não há sistemas de e-mail amplamente usados que distingam endereços diferentes por maiúsculas e minúsculas”
      O padrão diz uma coisa, mas as implementações se comportam de outra, e neste caso seguir apenas o texto do padrão causa problemas no mundo real
    • A forma que eu uso é salvar a capitalização original digitada pelo usuário, mas fazer as consultas sem diferenciar maiúsculas de minúsculas
      Assim, o e-mail é enviado para o endereço com a capitalização informada inicialmente, e o login funciona independentemente de maiúsculas e minúsculas
      A desvantagem é que não dá para ter dois usuários separados com e-mails que diferem apenas por maiúsculas/minúsculas, mas acho isso aceitável
    • Já vi casos em que, ao se cadastrar com e-mail, aquele e-mail virava o nome de usuário para login
      O e-mail não diferenciava maiúsculas de minúsculas, mas o nome de usuário gerado a partir do e-mail diferenciava maiúsculas de minúsculas, então, se você criasse uma conta com um e-mail contendo letras maiúsculas, precisava digitar exatamente aquela capitalização para entrar, e não conseguia fazer login com o e-mail ignorando maiúsculas/minúsculas
    • Vamos simplesmente acabar com as letras maiúsculas. É desperdício demais. Depois vêm os fusos horários, viva o UTC
      Em seguida, se eliminarmos também as diferenças de língua e cultura, dezenas de bilhões de linhas de código vão desaparecer; já consigo ouvir os repositórios encolhendo
    • Em teoria isso está certo, mas na prática já vi várias vezes sistemas em que, por bugs na implementação inicial, o mesmo e-mail foi salvo com diferentes combinações de maiúsculas e minúsculas
      Por exemplo, um registro de usuário tem JohnDoe@example.com e outro tem johndoe@example.com, embora claramente sejam a mesma pessoa
      Além disso, os valores vinham de sistemas diferentes, o que tornava tudo ainda mais complicado
      Acho que a matriz de riscos de e-mails sem distinção de maiúsculas/minúsculas é muito melhor que a de e-mails com distinção. Ou seja, o certo é transformar todos os e-mails em minúsculas, e The Copenhagen Book está certo nesse ponto
  • Muito bom. Sempre me incomodou que 90% dos materiais de segurança pareçam feitos para serem impossíveis de entender por quem não é especialista em segurança. Isso vale especialmente para materiais de criptografia
    Mas quase todas as páginas aqui são claras, concisas, diretas ao ponto e imediatamente aplicáveis, o que eu gostei bastante
    Só a página sobre curvas elípticas foi tão difícil de entender quanto outros materiais de criptografia

    • Para resumir por que criptografia é difícil, ela depende da teoria dos números e da suposição de complexidade N!=NP, isto é, da suposição de que existem funções unidirecionais/de alçapão
      Como o próprio funcionamento é matemático, acho que ela é inerentemente opaca
      Depois que entendi corpos finitos, curvas elípticas e, na prática, grupos de inteiros, consegui compreender muita criptografia, e geralmente era alguma forma do problema do logaritmo discreto
  • Seria bom também haver documentos alternativos sobre temas semelhantes. Por exemplo, algo como o OWASP Cheatsheet, mas com uma perspectiva mais prática.
    Respeito o documento, mas sou um pouco cético em relação a ele.
    O nome é bem grandioso. Chamar o documento como se tivesse sido escrito por pesquisadores universitários de Copenhagen é um excelente truque de marketing.
    É verdade que Lucia é uma biblioteca relativamente popular, mas isso não significa que ela promova boas práticas, nem que o autor deva ser visto como uma autoridade nessa área importante.
    Também há partes do design do Lucia de que não gosto. Quando um token de usuário está quase expirando, ele sugere estender a vida útil do token existente em vez de criar um novo token de segurança.
    Isso parece um comportamento muito inseguro, porque o token fica efetivamente vivo para sempre e pode continuar sendo explorado, violando a boa prática de segurança de limitar a vida útil dos tokens.
    Tanto Lucia quanto o “Copenhagen Book” recomendam essa abordagem: https://thecopenhagenbook.com/sessions#session-lifetime

    • O código no link que você publicou parece estender a sessão, não “estender” a vida útil do token.
      Essa é uma abordagem comum, normalmente chamada de sessão rolling.
      O token em si deveria ser imutável desde o início, portanto sua vida útil não deveria poder ser alterada; por isso, a renovação de token é feita entregando um novo token, não modificando o token original.
    • Se você descartar o token e responder ao cliente com um novo token, mas o cliente já tiver enviado uma nova requisição com o token anterior, essa requisição será rejeitada.
    • No contexto do Lucia, vejo nenhuma diferença entre estender uma sessão existente e criar uma nova sessão.
      No primeiro caso, um atacante rouba o token e o usa para sempre. No segundo caso, se o atacante roubar o token e receber um novo pouco antes da expiração, ele pode continuar se passando pelo usuário.
      Se o usuário for expulso, talvez perceba algo, mas a chance é baixa; e, para uma boa experiência do usuário, de qualquer forma é necessário um período de tolerância. Caso contrário, usuários legítimos também terão problemas com requisições paralelas.
      Dá para usar um segundo token, ou seja, um refresh token, mas isso apenas transfere o risco para esse token. Agora você precisa se preocupar com o refresh token sendo roubado e explorado para sempre.
      Refresh tokens são úteis porque evitam consultar o banco de dados a cada requisição. Em geral, tokens de sessão de curta duração podem ser validados sem banco de dados, como JWTs assinados.
      Mas, se forem roubados, não podem ser revogados e continuam válidos até expirar; portanto, para reduzir o dano, o tempo de expiração precisa ser curto.
      Já o refresh token consulta o banco de dados. O segundo token em si não adiciona segurança; quem adiciona segurança é a consulta ao banco de dados, porque ele pode ser removido do banco para ser revogado.
      O Lucia, pelo menos segundo os exemplos, sempre consulta o banco de dados, então é possível revogar o token a qualquer momento.
      Para reduzir o risco, é preciso permitir que o usuário veja e encerre sessões ativas. Se possível, é bom mostrar também horário, localização e informações do dispositivo. Ex.: “login feito ontem às 00h em Copenhagen a partir de um iPhone”.
      Também é possível avisar o usuário quando houver login a partir de uma nova localização ou dispositivo.
      No fim, não há como implementar sessões de longa duração de forma completamente segura.
    • Acho que você está atribuindo significado demais ao nome. Ainda assim, tenho curiosidade sobre abordagens alternativas para rotação de tokens de sessão.
      Acho que é uma boa observação, mas não posso dizer que sou especialista.
  • Há duas coisas que todo mundo deixa passar em OAuth, e elas não ficam muito evidentes.
    Fico feliz que alguém tenha apontado uma delas. Ao usar tokens, transações devem necessariamente ser usadas como mecanismo de bloqueio distribuído.
    Com refresh tokens, essa importância dobra, quadruplica. Se o mesmo token for usado duas ou mais vezes, esse usuário será desconectado.
    Não importa se o sistema roda em uma máquina ou em N máquinas. Se duas ou mais requisições com refresh token estiverem em andamento ao mesmo tempo — algo muito comum —, isso desconecta o usuário e frequentemente termina em 500.
    Refresh tokens são de uso único.
    A outra coisa que desenvolvedores e frameworks de autenticação deixam passar é o parâmetro “state”.

    • Não existe “uso único” sobre a rede. Invalidar imediatamente um refresh token assim que o servidor o recebe é procurar problema.
    • Acho isso complexo demais e inadequado para autenticação cotidiana.
      Olhando para a direção em que a autenticação em geral vem evoluindo hoje, parece estar se aproximando não de segurança por obscuridade, mas de instabilidade por obscuridade.
      Quando o estado da aplicação também se envolve, é preciso ajustar a lógica da aplicação à autenticação, e a aplicação precisa verificar se alguém roubou o refresh token.
    • Por motivos parecidos, a maioria dos sistemas implementa um período de tolerância para reutilização de refresh token.
      Transações sozinhas não resolvem. Por exemplo, se você abrir duas abas rapidamente, acabará atingindo o servidor duas vezes com o refresh token original.
    • É bem provável que você conheça o documento OAuth Threat Model.
      Esse documento prefere rotação de refresh tokens, mas também trata das dificuldades óbvias em ambientes de cluster: https://datatracker.ietf.org/doc/html/rfc6819#section-5.2.2....
    • Desculpe, mas aplicações reais não funcionam assim.
      Várias requisições sempre acontecem simultaneamente. Por exemplo, é comum o navegador iniciar com várias abas, ou um app de smartphone iniciar e enviar várias requisições de uma só vez.
  • Gostaria que mais sites dessem a opção “mantenha minha sessão sem expirar até eu sair; entendo o risco”
    Hoje em dia, o botão “remember me” não tem efeito nenhum
    Meu dia fica sendo interrompido por causa da expiração de sessões. O GitHub me irrita especialmente: como uso mais ou menos uma vez por semana, a sessão está sempre expirada e ainda força autenticação de dois fatores, então toda vez preciso pegar o celular e digitar o número
    A experiência do usuário é terrível, mas, mesmo sem ter evidências, acho que obrigar as pessoas a fazer login o tempo todo desse jeito as deixa cansadas e faz com que prestem menos atenção
    Se você faz login em um site várias vezes por semana, lá pelo 60º login fica mais fácil um site de phishing se meter no meio. Por outro lado, se uma conta na qual você quase nunca precisa fazer login de repente pede a senha, isso parece estranho e aumenta o estado de alerta
    No fim, as empresas precisam aprender que cada pessoa tem uma tolerância a risco e uma postura de segurança diferentes, e oferecer opções
    Além disso, fiquei tão irritado com as expirações frequentes de sessão e a autenticação de dois fatores do GitHub que migrei para o Gitea e desliguei a expiração. Esse foi 90% do motivo da mudança
    Como só é acessível pela minha rede, sinto que a segurança até melhorou. É totalmente possível uma empresa perder clientes por causa de um modelo de segurança inflexível

    • Este material tem boas recomendações sobre como lidar com a duração da sessão
      A ideia é, grosso modo, que se a sessão tiver sido usada nos últimos 30 dias, ela continue por mais 30 dias
      https://thecopenhagenbook.com/sessions#session-lifetime
    • Para mim, o Notion é o pior. Não pela frequência, mas porque ele realmente encerra sessões ativas e obriga a fazer login de novo
      O pior é que a sessão parece durar 1 ou 2 minutos a mais do que uma semana, então nesta semana fui expulso logo depois de começar a trabalhar no que tinha começado na semana passada
      Algumas semanas atrás, entrei para fazer anotações pouco antes de uma reunião recorrente e, por várias semanas seguidas, fui obrigado a fazer login no meio dessa reunião
    • Vale verificar se você não mudou algo nas configurações do navegador
      Há muitas configurações que podem neutralizar esses botões de “remember me”
      Pessoalmente, nunca tive problemas para permanecer logado em sites, incluindo o GitHub
    • Alguns provedores de autenticação limitam a duração dos tokens conforme o plano
    • Pelo menos dá para apreciar o teatro de segurança
  • Recentemente conheci o protocolo SRP e me surpreende que ele não seja mais usado ou mencionado
    É um protocolo relativamente simples que permite fazer prova de conhecimento zero e, ao mesmo tempo, criar um token de sessão entre servidor e cliente
    https://en.wikipedia.org/wiki/Secure_Remote_Password_protoco...

    • A adoção foi bloqueada por patentes
  • Gostei deste material. Muitos conselhos de segurança parecem obscuros e, às vezes, absurdos. Como um advogado aconselhando você a não fazer nada
    Este guia é agradavelmente conciso, fácil de acompanhar, fácil de entender e tem conselhos diretos, o que é ótimo
    Vou continuar acompanhando os comentários para ver se há opiniões contrárias ou ressalvas, mas acho que vou revisá-lo comparando com meu projeto de autenticação
    Uma coisa que eu gostaria é que houvesse uma seção sobre JWT. Mesmo que a opinião do autor seja “não use”, já seria bom dizer isso

    • A expressão “como um advogado aconselhando você a não fazer nada” faz sentido para mim
      Uma das críticas que faço com frequência às equipes de segurança é que elas passam muito tempo dizendo o que as pessoas não devem fazer, em vez de oferecer proativamente ferramentas ou métodos para que as pessoas façam de forma eficiente aquilo que querem fazer
    • Eu também gostaria de uma seção sobre SAML e uma visão geral de alto nível de como implementá-lo
    • Para fluxos por e-mail, como confirmação de e-mail ou redefinição de senha, recomendo deixar válido por alguns dias se o token secreto for forte o suficiente
      O e-mail pode ser visto como um sistema mais seguro, então talvez ele não esteja acessível imediatamente ou de qualquer lugar
  • Fico me perguntando se “auth” aqui significa autenticação (authn) ou autorização (authz)
    Pelo que parece, quer dizer autenticação, mas seria bom deixar isso claro

    • Como trata de tokens de sessão, senhas e WebAuthn, parece incluir os dois
  • Uma reclamação breve e um pouco relacionada: navegadores embutidos estão estragando a web
    Navegadores embutidos tornam impossível usar OAuth social. Em alguns casos é literalmente impossível; em outros, é praticamente impossível
    Quando você toca em um link no Instagram, por padrão ele abre no navegador do Instagram; se esse link tiver “Sign in with Google”, o Google bloqueia “navegadores inseguros” como o do Instagram, então não funciona
    Até “Sign in with Facebook” dá problema, embora a Meta seja dona tanto do Instagram quanto do Facebook. O navegador embutido do Facebook tem problemas parecidos

    • Navegadores embutidos têm muitos bons usos, mas navegar para links arbitrários não é um deles
      Quando clico em um link em lugares como o Slack, respondo a uma mensagem e depois volto ao navegador esperando que aquela página esteja lá, mas o Slack a engoliu dentro do próprio navegador e ela não está em lugar nenhum, isso quase sempre é inútil
      Felizmente, acabei de verificar e há uma forma de desativar o navegador embutido no Slack