PARTE I: Como entrar
Vamos supor que você já sabe como criar um formulário HTML de login + senha que POST coloca os valores em um script no servidor para autenticação. As seções abaixo tratarão de padrões para uma autenticação prática sólida e como evitar as armadilhas de segurança mais comuns.
Para HTTPS ou não para HTTPS?
A menos que a conexão já esteja segura (ou seja, tunelada através de HTTPS usando SSL / TLS), os valores do seu formulário de login serão enviados em texto não criptografado, permitindo que qualquer pessoa que esteja ouvindo a linha entre o navegador e o servidor da Web possa ler os logins à medida que passam através. Esse tipo de escutas telefônicas é feito rotineiramente pelos governos, mas, em geral, não abordaremos os fios 'de propriedade' além de dizer o seguinte: basta usar HTTPS.
Em essência, a única maneira prática de se proteger contra escutas telefônicas / detecção de pacotes durante o login é usando HTTPS ou outro esquema de criptografia baseada em certificado (por exemplo, TLS ) ou um esquema de resposta a desafios comprovado e testado (por exemplo, o Diffie-Hellman SRP baseado em Qualquer outro método pode ser facilmente contornado por um invasor que escuta.
Obviamente, se você quiser ser um pouco impraticável, também poderá empregar algum tipo de esquema de autenticação de dois fatores (por exemplo, o aplicativo Google Authenticator, um livro de códigos físico 'estilo de guerra fria' ou um dongle gerador de chave RSA). Se aplicado corretamente, isso pode funcionar mesmo com uma conexão não segura, mas é difícil imaginar que um desenvolvedor esteja disposto a implementar autenticação de dois fatores, mas não SSL.
(Não) Role seu próprio criptografia / hash JavaScript
Dado o custo percebido (embora agora evitável ) e a dificuldade técnica de configurar um certificado SSL em seu site, alguns desenvolvedores são tentados a lançar seus próprios esquemas de hash ou criptografia no navegador para evitar a transmissão de logins de texto não criptografado por um fio não seguro.
Embora este seja um pensamento nobre, é essencialmente inútil (e pode ser uma falha de segurança ), a menos que seja combinado com um dos itens acima - ou seja, proteger a linha com criptografia forte ou usar uma resposta de desafio testada e comprovada mecanismo (se você não souber o que é isso, saiba que é um dos mais difíceis de provar, mais difíceis de projetar e mais difíceis de implementar conceitos em segurança digital).
Embora seja verdade que o hash da senha possa ser eficaz contra a divulgação de senhas , ele é vulnerável a ataques de repetição, ataques / sequestros do tipo Man-In-The-Middle (se um invasor puder injetar alguns bytes na sua página HTML não segura antes de atingir seu objetivo). navegador, eles podem simplesmente comentar o hash no JavaScript) ou ataques de força bruta (desde que você esteja entregando ao invasor o nome de usuário, a senha salt e a hash).
CAPTCHAS contra a humanidade
O CAPTCHA visa impedir uma categoria específica de ataque: dicionário automatizado / tentativa e erro de força bruta sem operador humano. Não há dúvida de que essa é uma ameaça real; no entanto, existem maneiras de lidar com isso sem problemas que não exigem um CAPTCHA, esquemas de otimização de login do lado do servidor especificamente projetados adequadamente - discutiremos mais adiante.
Saiba que as implementações de CAPTCHA não são criadas da mesma forma; eles geralmente não são solucionáveis por humanos, a maioria deles é realmente ineficaz contra bots, todos eles são ineficazes contra mão-de-obra barata no terceiro mundo (de acordo com a OWASP , a taxa atual de oficinas é de US $ 12 por 500 testes) e algumas implementações podem ser tecnicamente ilegal em alguns países (consulte a OWASP Authentication Cheat Sheet ). Se você precisar usar um CAPTCHA, use o reCAPTCHA do Google , pois é difícil para OCR por definição (já que usa digitalizações de livros já classificadas incorretamente por OCR) e tenta muito ser amigável.
Pessoalmente, costumo achar CAPTCHAS irritante e usá-los apenas como último recurso quando um usuário não loga várias vezes e os atrasos de limitação são atingidos no máximo. Isso raramente acontece o suficiente para ser aceitável e fortalece o sistema como um todo.
Armazenamento de senhas / verificação de logins
Finalmente, isso pode ser um conhecimento comum depois de todos os hacks e vazamentos de dados de usuários altamente divulgados que vimos nos últimos anos, mas é preciso dizer: Não armazene senhas em texto não criptografado em seu banco de dados. Os bancos de dados dos usuários são rotineiramente hackeados, vazados ou colhidos através da injeção de SQL e, se você estiver armazenando senhas brutas em texto sem formatação, é um jogo instantâneo para sua segurança de login.
Portanto, se você não pode armazenar a senha, como verifica se a combinação de logon + senha POSTADA no formulário de logon está correta? A resposta é o hash usando uma função de derivação de chave . Sempre que um novo usuário é criado ou uma senha é alterada, você pega a senha e a executa através de um KDF, como Argon2, bcrypt, scrypt ou PBKDF2, transformando a senha de texto não criptografado ("correcthorsebatterystaple") em uma cadeia longa e de aparência aleatória , que é muito mais seguro para armazenar em seu banco de dados. Para verificar um logon, execute a mesma função de hash na senha digitada, desta vez passando no salt e compare a cadeia de hash resultante com o valor armazenado em seu banco de dados. Argônio2, bcrypt e scrypt já armazenam o sal com o hash. Confira este artigo em sec.stackexchange para obter informações mais detalhadas.
A razão pela qual um sal é usado é que o hash por si só não é suficiente - você deve adicionar o chamado 'salt' para proteger o hash contra as tabelas do arco-íris . Um salt impede efetivamente que duas senhas que correspondam exatamente sejam armazenadas com o mesmo valor de hash, impedindo que todo o banco de dados seja verificado em uma execução, se um invasor estiver executando um ataque de adivinhação de senha.
Um hash criptográfico não deve ser usado para armazenamento de senhas porque as senhas selecionadas pelo usuário não são fortes o suficiente (ou seja, geralmente não contêm entropia suficiente) e um ataque de suposição de senha pode ser concluído em um tempo relativamente curto por um invasor com acesso aos hashes. É por isso que os KDFs são usados - eles efetivamente "esticam a chave" , o que significa que toda suposição de senha que um invasor faz causa várias repetições do algoritmo de hash, por exemplo, 10.000 vezes, o que faz com que o invasor adivinhe a senha 10.000 vezes mais devagar.
Dados da sessão - "Você está logado como Spiderman69"
Depois que o servidor verifica o login e a senha no banco de dados do usuário e encontra uma correspondência, o sistema precisa de uma maneira de lembrar que o navegador foi autenticado. Esse fato só deve ser armazenado no lado do servidor nos dados da sessão.
Se você não estiver familiarizado com os dados da sessão, veja como ele funciona: Uma única sequência gerada aleatoriamente é armazenada em um cookie expirado e usada para referenciar uma coleção de dados - os dados da sessão - armazenados no servidor. Se você estiver usando uma estrutura MVC, isso sem dúvida já será tratado.
Se possível, verifique se o cookie da sessão tem os sinalizadores seguro e HTTP Only definidos quando enviados ao navegador. O sinalizador HttpOnly fornece alguma proteção contra o cookie que está sendo lido através do ataque XSS. O sinalizador seguro garante que o cookie seja enviado apenas de volta via HTTPS e, portanto, protege contra ataques de detecção de rede. O valor do cookie não deve ser previsível. Quando um cookie referenciando uma sessão inexistente é apresentado, seu valor deve ser substituído imediatamente para evitar a fixação da sessão .
PARTE II: Como permanecer logado - a infame caixa de seleção "Remember Me"
Cookies de login persistentes (funcionalidade "lembre-se de mim") são uma zona de perigo; por um lado, são totalmente tão seguros quanto os logons convencionais quando os usuários entendem como lidar com eles; e, por outro lado, eles representam um enorme risco de segurança nas mãos de usuários descuidados, que podem usá-los em computadores públicos e esquecer de fazer logout, e que podem não saber o que são os cookies do navegador ou como excluí-los.
Pessoalmente, gosto de logins persistentes para os sites que visito regularmente, mas sei como lidar com eles com segurança. Se você acredita que seus usuários sabem o mesmo, use logons persistentes com a consciência limpa. Caso contrário - bem, você pode se inscrever na filosofia de que os usuários que são descuidados com suas credenciais de login criaram isso caso fossem invadidos. Não é como se estivéssemos na casa de nossos usuários e arrancássemos todas as anotações do Post-It com senhas que estavam alinhadas na borda de seus monitores.
Claro, alguns sistemas não pode dar ao luxo de ter quaisquer contas invadidas; para esses sistemas, não há como justificar a existência de logins persistentes.
Se você decidir implementar cookies de login persistentes, é assim que você faz:
Primeiro, reserve um tempo para ler o artigo da Paragon Initiative sobre o assunto. Você precisará acertar vários elementos, e o artigo explica muito bem cada um deles.
E apenas para reiterar uma das armadilhas mais comuns, NÃO ARMAZENE O BOLINHO DE LOGIN PERSISTENTE (TOKEN) NA SUA BASE DE DADOS, APENAS UM HASH! O token de logon é equivalente à senha; portanto, se um invasor colocar as mãos em seu banco de dados, ele poderá usar os tokens para efetuar login em qualquer conta, como se fossem combinações de logon e senha de texto não criptografado. Portanto, use o hash (de acordo com https://security.stackexchange.com/a/63438/5002, um hash fraco funcionará bem para esse propósito) ao armazenar tokens de login persistentes.
PARTE III: Usando perguntas secretas
Não implemente 'perguntas secretas' . O recurso 'perguntas secretas' é um antipadrão de segurança. Leia o artigo do link número 4 da lista DEVE LER. Você pode perguntar a Sarah Palin sobre isso, depois do Yahoo! a conta de email foi hackeada durante uma campanha presidencial anterior porque a resposta para sua pergunta de segurança foi ... "Wasilla High School"!
Mesmo com perguntas especificadas pelo usuário, é altamente provável que a maioria dos usuários escolha:
Uma pergunta secreta 'padrão', como o nome de solteira da mãe ou o animal de estimação favorito
Uma simples trivialidade que qualquer pessoa poderia extrair de seu blog, perfil do LinkedIn ou similar
Qualquer pergunta que seja mais fácil de responder do que adivinhar sua senha. Qual, para qualquer senha decente, é toda pergunta que você pode imaginar
Em conclusão, as questões de segurança são inerentemente inseguras em praticamente todas as suas formas e variações e não devem ser empregadas em um esquema de autenticação por qualquer motivo.
A verdadeira razão pela qual as perguntas de segurança ainda existem na natureza é que elas economizam convenientemente o custo de algumas chamadas de suporte de usuários que não podem acessar seus emails para obter um código de reativação. Isso às custas da segurança e da reputação de Sarah Palin. Vale a pena? Provavelmente não.
PARTE IV: Funcionalidade de senha esquecida
Eu já mencionei por que você nunca deve usar perguntas de segurança para lidar com senhas de usuário esquecidas / perdidas; Também não é necessário dizer que você nunca deve enviar aos usuários por email suas senhas reais. Existem pelo menos mais duas armadilhas comuns demais para evitar neste campo:
Não redefina uma senha esquecida para uma senha forte gerada automaticamente - essas senhas são notoriamente difíceis de lembrar, o que significa que o usuário deve alterá-las ou anotá-las - digamos, em um Post-It amarelo brilhante na borda do monitor. Em vez de definir uma nova senha, permita que os usuários escolham uma nova imediatamente - e é isso que eles querem fazer de qualquer maneira. (Uma exceção a isso pode ser se os usuários estiverem usando universalmente um gerenciador de senhas para armazenar / gerenciar senhas que normalmente seriam impossíveis de lembrar sem anotá-las).
Sempre faça o hash do código / token da senha perdida no banco de dados. NOVAMENTE , esse código é outro exemplo de Senha equivalente, portanto, DEVE ser feito um hash no caso de um invasor colocar as mãos em seu banco de dados. Quando um código de senha perdida for solicitado, envie o código de texto sem formatação para o endereço de e-mail do usuário, faça o hash, salve o hash no seu banco de dados - e jogue fora o original . Assim como uma senha ou um token de login persistente.
Uma observação final: sempre verifique se sua interface para inserir o 'código de senha perdida' é pelo menos tão segura quanto o próprio formulário de login, ou um invasor simplesmente usará isso para obter acesso. Certifique-se de gerar 'códigos de senha perdidos' muito longos (por exemplo, 16 caracteres alfanuméricos com distinção entre maiúsculas e minúsculas) é um bom começo, mas considere adicionar o mesmo esquema de otimização que você faz para o próprio formulário de login.
PARTE V: Verificando a força da senha
Primeiro, você deve ler este pequeno artigo para verificar a realidade: As 500 senhas mais comuns
Ok, talvez a lista não seja a lista canônica das senhas mais comuns em qualquer sistema em qualquer lugar , mas é uma boa indicação de quão mal as pessoas escolherão suas senhas quando não houver uma política aplicada. Além disso, a lista parece assustadoramente próxima de casa quando você a compara às análises publicamente disponíveis de senhas roubadas recentemente.
Portanto: sem requisitos mínimos de força de senha, 2% dos usuários usam uma das 20 principais senhas mais comuns. Significado: se um invasor receber apenas 20 tentativas, uma em cada 50 contas no seu site poderá ser quebrada.
Para impedir isso, é necessário calcular a entropia de uma senha e aplicar um limite. A publicação especial 800-63 do Instituto Nacional de Padrões e Tecnologia (NIST) tem um conjunto de sugestões muito boas. Isso, quando combinado com uma análise de layout de dicionário e teclado (por exemplo, 'qwertyuiop' é uma senha incorreta), pode rejeitar 99% de todas as senhas mal selecionadas em um nível de 18 bits de entropia. Simplesmente calcular a força da senha e mostrar um medidor de força visual para um usuário é bom, mas insuficiente. A menos que seja imposto, muitos usuários provavelmente o ignorarão.
E, para uma visão refrescante da facilidade de uso de senhas de alta entropia, o Password Strength xkcd de Randall Munroe é altamente recomendado.
Utilize a API Fui Pwned de Troy Hunt para verificar senhas de usuários contra senhas comprometidas em violações de dados públicos.
PARTE VI: Muito Mais - Ou: Evitando Tentativas de Login Rápido
Primeiro, dê uma olhada nos números: Velocidades de recuperação de senha - Quanto tempo sua senha ficará em pé
Se você não tiver tempo para examinar as tabelas nesse link, veja a lista delas:
Não leva praticamente tempo para quebrar uma senha fraca, mesmo se você a estiver quebrando com um ábaco
Praticamente não leva tempo para decifrar uma senha alfanumérica de 9 caracteres, caso não seja sensível a maiúsculas e minúsculas
Não leva praticamente tempo para decifrar uma senha intrincada, com letras e números e letras maiúsculas e minúsculas, se tiver menos de 8 caracteres (um PC de mesa pode pesquisar em todo o espaço de teclas até 7 caracteres em uma questão). de dias ou até horas)
No entanto, levaria uma quantidade excessiva de tempo para quebrar até mesmo uma senha de 6 caracteres, se você estivesse limitado a uma tentativa por segundo!
Então, o que podemos aprender com esses números? Bem, mas podemos nos concentrar na parte mais importante: o fato de impedir um grande número de tentativas sucessivas de login rápido (ou seja, o ataque de força bruta ) realmente não é tão difícil. Mas impedi-lo corretamente não é tão fácil quanto parece.
De um modo geral, você tem três opções eficazes contra ataques de força bruta (e ataques de dicionário, mas como você já está empregando uma política forte de senhas, elas não devem ser um problema) :
Apresente um CAPTCHA após N tentativas fracassadas (irritante como o inferno e muitas vezes ineficaz - mas estou me repetindo aqui)
Bloquear contas e exigir verificação de e-mail após N tentativas fracassadas (este é um ataque de negação de serviço esperando para acontecer)
E, finalmente, a limitação de login : ou seja, definir um atraso de tempo entre as tentativas após N tentativas fracassadas (sim, os ataques de DoS ainda são possíveis, mas pelo menos são muito menos prováveis e muito mais complicados de executar).
Prática recomendada nº 1: um pequeno atraso que aumenta com o número de tentativas com falha, como:
- 1 tentativa falhada = sem atraso
- 2 tentativas com falha = atraso de 2 s
- 3 tentativas com falha = atraso de 4 s
- 4 tentativas com falha = atraso de 8 s
- 5 tentativas com falha = atraso de 16 s
- etc.
O DoS que atacar esse esquema seria muito impraticável, pois o tempo de bloqueio resultante é um pouco maior que a soma dos tempos de bloqueio anteriores.
Para esclarecer: O atraso não é um atraso antes de retornar a resposta ao navegador. É mais como um tempo limite ou refratário durante o qual tentativas de login para uma conta específica ou para um endereço IP específico não serão aceitas ou avaliadas. Ou seja, credenciais corretas não retornarão em um logon bem-sucedido e credenciais incorretas não acionarão um aumento de atraso.
Prática recomendada nº 2: um atraso médio que entra em vigor após N tentativas fracassadas, como:
- 1-4 tentativas com falha = sem atraso
- 5 tentativas com falha = atraso de 15 a 30 minutos
DoS atacando esse esquema seria bastante impraticável, mas certamente factível. Além disso, pode ser relevante observar que um atraso tão longo pode ser muito irritante para um usuário legítimo. Usuários esquecidos vão gostar de você.
Prática recomendada nº 3: combinando as duas abordagens - um atraso fixo e curto que entra em vigor após N tentativas fracassadas, como:
- 1-4 tentativas com falha = sem atraso
- 5+ tentativas com falha = atraso de 20 s
Ou, um atraso crescente com um limite superior fixo, como:
- 1 tentativa falhada = atraso de 5 s
- 2 tentativas com falha = atraso de 15 s
- 3+ tentativas com falha = atraso de 45 s
Esse esquema final foi retirado das sugestões de melhores práticas da OWASP (link 1 da lista DEVER-LER) e deve ser considerado uma boa prática, mesmo que seja reconhecidamente do lado restritivo.
Como regra geral, no entanto, eu diria: quanto mais forte for sua política de senha, menos você precisará corrigir os atrasos nos usuários. Se você precisar de senhas fortes (alfanuméricas com distinção entre maiúsculas e minúsculas + símbolos e números obrigatórios) com mais de 9 caracteres, poderá fornecer aos usuários de 2 a 4 tentativas de senha sem atraso antes de ativar a regulagem.
O DoS que atacar esse esquema final de limitação de login seria muito impraticável. E, como toque final, sempre permita a passagem de logons persistentes (cookies) (e / ou um formulário de login verificado pelo CAPTCHA), para que os usuários legítimos nem se demorem enquanto o ataque estiver em andamento . Dessa forma, o ataque DoS muito impraticável se torna um ataque extremamente impraticável.
Além disso, faz sentido executar uma otimização mais agressiva nas contas de administrador, pois esses são os pontos de entrada mais atraentes
PARTE VII: Ataques Distribuídos de Força Bruta
Além disso, invasores mais avançados tentarão burlar a limitação de logon 'espalhando suas atividades':
Distribuindo as tentativas em uma botnet para impedir a sinalização de endereço IP
Em vez de escolher um usuário e tentar as 50.000 senhas mais comuns (que não podem, por causa de nossa limitação), eles escolherão a senha mais comum e tentarão contra 50.000 usuários. Dessa forma, eles não apenas evitam medidas de tentativas máximas como CAPTCHAs e limitação de login, mas também aumentam suas chances de sucesso, pois a senha mais comum número 1 é muito mais provável que o número 49.995
Espaçando as solicitações de login para cada conta de usuário, digamos, com 30 segundos de diferença, para se esgueirar sob o radar
Aqui, a melhor prática seria registrar o número de logons com falha, em todo o sistema , e usar uma média de execução da frequência de login incorreto do seu site como base para um limite superior que você impõe a todos os usuários.
Abstrato demais? Deixe-me reformular:
Digamos que seu site teve uma média de 120 logins inválidos por dia nos últimos 3 meses. Usando isso (média de execução), seu sistema pode definir o limite global para 3 vezes isso - ou seja. 360 tentativas com falha ao longo de um período de 24 horas. Então, se o número total de tentativas com falha em todas as contas exceder esse número em um dia (ou melhor ainda, monitorar a taxa de aceleração e disparar em um limite calculado), ele ativará a otimização de logon em todo o sistema - significando pequenos atrasos para TODOS os usuários (ainda, com exceção dos logins de cookies e / ou logons CAPTCHA de backup).
Também publiquei uma pergunta com mais detalhes e uma discussão realmente boa de como evitar pitfals complicados em combater ataques distribuídos de força bruta
PARTE VIII: Autenticação de dois fatores e provedores de autenticação
As credenciais podem ser comprometidas, seja por explorações, senhas sendo anotadas e perdidas, laptops com chaves roubadas ou usuários inserindo logins em sites de phishing. Os logins podem ser protegidos ainda mais com autenticação de dois fatores, que usa fatores fora de banda, como códigos de uso único recebidos de uma ligação telefônica, mensagem SMS, aplicativo ou dongle. Vários provedores oferecem serviços de autenticação de dois fatores.
A autenticação pode ser completamente delegada a um serviço de logon único, onde outro provedor lida com a coleta de credenciais. Isso leva o problema a um terceiro confiável. Google e Twitter fornecem serviços SSO baseados em padrões, enquanto o Facebook fornece uma solução proprietária semelhante.
Links obrigatórios sobre autenticação na Web
- Guia da OWASP para autenticação / OWASP Authentication Cheat Sheet
- Prós e contras da autenticação de clientes na Web (artigo de pesquisa do MIT muito legível)
- Wikipedia: cookie HTTP
- Perguntas de conhecimento pessoal para autenticação de fallback: perguntas de segurança na era do Facebook (artigo de pesquisa de Berkeley muito legível)