Qual é a melhor contramedida da Força Bruta Distribuída?

151

Primeiro, um pouco de histórico: não é segredo que estou implementando um sistema auth + auth para o CodeIgniter, e até agora estou ganhando (por assim dizer). Mas me deparei com um desafio bastante não trivial (um que a maioria das bibliotecas de autenticação sente falta inteiramente, mas insisto em tratá-lo adequadamente): como lidar de maneira inteligente com ataques de força bruta em grande escala, distribuídos e com nome de usuário variável .

Conheço todos os truques de sempre:

  1. Limitar o número de tentativas com falha por IP / host e negar o acesso dos criminosos (por exemplo, Fail2Ban) - que não funciona mais desde que as botnets se tornaram mais inteligentes
  2. Combinando o que foi dito acima com uma lista negra de IPs / hosts 'ruins' conhecidos (por exemplo, DenyHosts) - que depende de botnets que caem no 1º lugar, o que cada vez mais não acontece
  3. As listas brancas de IP / host combinadas com a autenticação tradicional (infelizmente inútil para usuários dinâmicos de IP e a alta rotatividade na maioria dos sites)
  4. Definir um limite em todo o site para o número de tentativas com falha dentro de um período de N minutos / hora e limitar (suspender) todas as tentativas de login depois disso por alguns minutos / horas (com o problema de que o DoS está atacando você se torna brincadeira de criança com botnet)
  5. Assinaturas digitais obrigatórias (certificados de chave pública) ou tokens de hardware RSA para todos os usuários sem opção de login / senha (sem dúvida uma solução sólida, mas apenas prática para serviços dedicados e fechados)
  6. Aplicadas esquemas de senha ultra-fortes (por exemplo> 25 caracteres sem sentido com símbolos - novamente, muito prático para os usuários casuais)
  7. E, finalmente, os CAPTCHAs (que podem funcionar na maioria dos casos, mas são irritantes para os usuários e praticamente inúteis contra um invasor determinado e engenhoso )

Agora, essas são apenas as ideias teoricamente viáveis. Existem muitas idéias inúteis que explodem o site (por exemplo, ataques triviais de DoS). O que eu quero é algo melhor. E por melhor, quero dizer:

  • Ele deve ser seguro (+) contra ataques de força bruta e DoS e não introduzir novas vulnerabilidades que possam permitir que um bot um pouco mais furtivo continue operando sob o radar

  • Tem que ser automatizado. Se exigir que um operador humano verifique cada login ou monitore atividades suspeitas, isso não funcionará em um cenário do mundo real

  • Ele deve ser viável para uso na Web convencional (por exemplo, alto churn, alto volume e registro aberto que pode ser executado por não programadores)

  • Não pode impedir a experiência do usuário a ponto de usuários casuais ficarem irritados ou frustrados (e potencialmente abandonar o site)

  • Não pode envolver gatinhos, a menos que sejam gatinhos realmente seguros

(+) Por 'seguro', quero dizer pelo menos tão seguro quanto a capacidade de um usuário paranóico de manter sua senha secreta

Então - vamos ouvir! Como você faria isso ? Você conhece uma prática recomendada que eu não mencionei (por favor, diga que sim)? Admito que tenho uma ideia própria (combinando idéias de 3 e 4), mas deixarei os verdadeiros especialistas falarem antes de me envergonhar ;-)

Jens Roland
fonte

Respostas:

68

Tudo bem, basta parar; aqui está o que eu vim até agora

(desculpe, post longo à frente. Seja corajoso, amigo, a jornada valerá a pena)

Combinando os métodos 3 e 4 da postagem original em uma espécie de lista branca 'fuzzy' ou dinâmica, e então - e aqui está o truque - não bloquear IPs não incluídos na lista de permissões, limitando-os ao inferno .

Observe que esta medida serve apenas para frustrar esse tipo muito específico de ataque. Na prática, é claro, funcionaria em combinação com outras abordagens de práticas recomendadas para autenticação: limitação de nome de usuário fixo, limitação por IP, política de senha forte imposta por código, logon de cookie não acelerado, hash todos os equivalentes de senha antes de salvá-los, nunca usando perguntas de segurança etc.

Pressupostos sobre o cenário de ataque

Se um invasor está direcionando nomes de usuário variáveis, a limitação de nosso nome de usuário não é acionada. Se o invasor estiver usando uma botnet ou tiver acesso a um grande intervalo de IPs, nossa limitação de IP será impotente. Se o invasor pré-rastreou nossa lista de usuários (geralmente possível em serviços da web de registro aberto), não podemos detectar um ataque contínuo com base no número de erros de 'usuário não encontrado'. E se aplicarmos uma limitação restritiva em todo o sistema (todos os nomes de usuário, todos os IPs), qualquer ataque desse tipo prejudicará todo o site durante a duração do ataque mais o período de limitação.

Então, precisamos fazer outra coisa.

A primeira parte da contramedida: lista de permissões

O que podemos ter certeza é que o invasor não é capaz de detectar e falsificar dinamicamente os endereços IP de vários milhares de nossos usuários (+). O que torna a lista de permissões viável. Em outras palavras: para cada usuário, armazenamos uma lista dos IPs (com hash) de onde o usuário efetuou o login anteriormente (recentemente).

Portanto, nosso esquema de lista de permissões funcionará como uma 'porta da frente' trancada, na qual um usuário deve estar conectado a partir de um dos seus IPs 'bons' reconhecidos para fazer login. Um ataque de força bruta a essa 'porta da frente' seria praticamente impossível (+).

(+) a menos que o invasor 'seja dono' do servidor, de todas as caixas de nossos usuários ou da própria conexão - e nesses casos, não temos mais um problema de 'autenticação', temos um pull-the genuíno do tamanho de uma franquia situação FUBAR

A segunda parte da contramedida: limitação em todo o sistema de IPs não reconhecidos

Para fazer com que uma lista de permissões funcione para um serviço da Web de registro aberto, em que os usuários trocam de computador com frequência e / ou se conectam a partir de endereços IP dinâmicos, precisamos manter uma 'porta de gato' aberta para usuários que se conectam a partir de IPs não reconhecidos. O truque é projetar essa porta para que as botnets fiquem presas e os usuários legítimos sejam incomodados o menos possível .

No meu esquema, isso é conseguido através da definição de um número máximo muito restritivo de tentativas de logon com falha por IPs não aprovados durante, digamos, um período de 3 horas (pode ser mais sensato usar um período mais curto ou mais longo, dependendo do tipo de serviço) e tornando essa restrição global , ie. para todas as contas de usuário.

Mesmo uma força bruta lenta (1-2 minutos entre tentativas) seria detectada e frustrada de maneira rápida e eficaz usando esse método. Obviamente, uma força bruta realmente lenta ainda pode passar despercebida, mas velocidades muito baixas derrotam o próprio objetivo do ataque da força bruta.

O que espero conseguir com esse mecanismo de limitação é que, se o limite máximo for atingido, nossa 'porta do gato' se fecha por um tempo, mas nossa porta da frente permanece aberta para usuários legítimos que se conectam por meios usuais:

  • Conectando-se a partir de um de seus IPs reconhecidos
  • Ou usando um cookie de login persistente (de qualquer lugar)

Os únicos usuários legítimos que seriam afetados durante um ataque - ie. enquanto a limitação foi ativada - seriam usuários sem cookies de login persistentes que estavam fazendo login de um local desconhecido ou com um IP dinâmico. Esses usuários não conseguiriam fazer login até que a limitação acabasse (o que poderia levar um tempo, se o invasor mantivesse sua botnet em execução, apesar da limitação).

Para permitir que esse pequeno subconjunto de usuários atravesse a porta do gato selada de outro modo, mesmo enquanto os bots ainda estavam martelando, eu empregaria um formulário de login de 'backup' com um CAPTCHA. Portanto, quando você exibir a mensagem "Desculpe, mas não pode fazer login neste endereço IP no momento", inclua um link que diz " login seguro para backup - SOMENTE PARA HUMANOS ( bots: sem mentir ) ". Brincadeira à parte, quando clicarem nesse link, forneça a eles um formulário de login autenticado pelo reCAPTCHA que ignora a otimização em todo o site. Dessa forma, se eles são humanos E sabem o login + senha correto (e conseguem ler CAPTCHAs), eles nunca terão o serviço negado, mesmo se estiverem se conectando a partir de um host desconhecido e não estiverem usando o cookie de login automático.

Ah, e apenas para esclarecer: Como eu considero os CAPTCHAs geralmente ruins, a opção de login 'backup' aparece quando a limitação estiver ativa .

Não há como negar que um ataque sustentado como esse ainda constituiria uma forma de ataque DoS, mas com o sistema descrito em vigor, isso afetaria apenas o que eu suspeito ser um pequeno subconjunto de usuários, ou seja, pessoas que não usam o O cookie "lembra-me" E, por acaso, está efetuando login enquanto um ataque está ocorrendo E não está efetuando login em nenhum de seus IPs habituais E que não conseguem ler CAPTCHAs. Somente aqueles que podem dizer não a TODOS esses critérios - especificamente bots e pessoas com deficiência muito azaradas - serão recusados ​​durante um ataque de bot.

EDIT: Na verdade, pensei em uma maneira de permitir que usuários desafiados pelo CAPTCHA passassem durante um 'bloqueio': em vez de ou como um complemento para o login de backup do CAPTCHA, forneça ao usuário a opção de ter um uso único , código de bloqueio específico do usuário enviado para seu e-mail, que ele pode usar para ignorar a limitação. Definitivamente, isso ultrapassa meu limite de 'irritação', mas como é usado apenas como último recurso para um pequeno subconjunto de usuários, e como ainda é melhor do que ser bloqueado na sua conta, seria aceitável.

(Além disso, observe que nada disso acontece se o ataque for menos sofisticado do que a desagradável versão distribuída que eu descrevi aqui. Se o ataque vier de apenas alguns IPs ou apenas de alguns nomes de usuário, ele será frustrado muito antes. e sem consequências em todo o site)


Portanto, essa é a contramedida que implementarei na minha biblioteca de autenticação, uma vez que estou convencido de que é bom e que não há uma solução muito mais simples que eu tenha perdido. O fato é que existem muitas maneiras sutis de fazer coisas erradas em segurança, e não estou acima de fazer suposições falsas ou lógica irremediavelmente falho. Então, por favor, todo e qualquer feedback, crítica e aprimoramento, sutilezas etc. são muito apreciados.

Jens Roland
fonte
1
Talvez você possa gerar uma senha 'especial' para cada usuário que possa usar se estiver no modo de bloqueio (e eles estiverem se conectando a partir de um novo IP etc.), sendo essa senha especial suficientemente complicada que não é possível usar força bruta?
Douglas Leeder 27/01/09
1
Isso poderia funcionar, mas apenas se os usuários se lembrarem dessas senhas, mesmo que não as usassem antes (esses tipos de ataque não são comuns e nenhum botmaster que se preza se incomodaria em manter uma funcionando por muito tempo depois de ser estrangulada). O risco é grande demais e eles simplesmente não conseguiam se lembrar.
Jens Roland
1
No entanto, um método que pode funcionar definitivamente é fornecer um link 'envie-me um código de bloqueio' para esses usuários, permitindo que eles recebam um email contendo um token específico de usuário de uso único que permitiria o login, ignorando o estrangulamento.
Jens Roland
1
@ Abtin: Boa ideia, exceto que seria 'entrar na corrida armamentista' - ie. iniciando um 'quem pode ser mais esperto do que quem' com as pessoas que criam listas de senhas para ataques de dicionário. Eu acho que a melhor maneira seria a de aplicar uma política de senha forte para que haja estão há senhas fracas
Jens Roland
1
@OrestisP .: Você está perdendo o ponto do ataque distribuído - o número de tentativas inválidas de cada IP é mínimo, portanto o bloqueio por IP não pode funcionar. Além disso, a pergunta descreve especificamente um ataque automatizado de força bruta; portanto, 1) o invasor não é humano, mas uma rede de máquinas zumbis (que não pode usar o login captcha); e 2) a natureza da força bruta do ataque exige um número muito alto de tentativas de logon para garantir o sucesso, o que significa que o captcha resolvendo para uma loja de suor em algum lugar não é viável (embora possível se o atacante for bem financiado e determinado o suficiente).
Jens Roland #
17

Alguns passos simples:

Coloque na lista negra certos nomes de usuário comuns e use-os como um honeypot. Admin, convidado, etc ... Não deixe ninguém criar contas com esses nomes; portanto, se alguém tentar fazer login, você sabe que é alguém que está fazendo algo que não deveria.

Verifique se alguém com poder real no site possui uma senha segura. Exija que os administradores / moderadores tenham senhas mais longas com uma mistura de letras, números e símbolos. Rejeite senhas trivialmente simples de usuários regulares com uma explicação.

Uma das coisas mais simples que você pode fazer é dizer às pessoas quando alguém tentou fazer login em sua conta e fornecer um link para relatar o incidente, se não fossem elas. Uma mensagem simples quando eles fazem login, como "Alguém tentou fazer login na sua conta às 04h20, quarta-feira blá blá. Clique aqui se este não for você." Permite manter algumas estatísticas sobre ataques. Você pode intensificar as medidas de monitoramento e segurança se perceber que há um aumento repentino de acessos fraudulentos.

patros
fonte
Belas pensamentos. Definitivamente, eu estava planejando implementar uma política de senha automática que varia dinamicamente com o nível de privilégio do usuário. A ideia do honeypot pode funcionar para alguns tipos de ataque, mas se o ataque for distribuído, o bloqueio dos IPs que caem não será eficaz.
Jens Roland
No que diz respeito à 'Última tentativa de login', essa é uma boa estratégia para usuários avançados (que eu aposto que é a razão pela qual a SO faz isso), mas tem duas fraquezas: (a) não trata do problema da intrusão, apenas relata que pode ter acontecido, e (b), a maioria de usuários é apenas não me lembro / cuidado
Jens Roland
1
Sim, o honeypot e os relatórios de usuários são mais sobre coleta de informações. Eles podem fornecer algumas métricas valiosas para informar se / quando um ataque lento de força bruta está acontecendo.
Patros
2
Para o honeypot, não seria melhor tratar qualquer nome de usuário inexistente como suspeito do que apenas usar uma lista fixa de nomes de usuário com problemas conhecidos? Você deseja evitar o bloqueio de usuários que digitaram incorretamente seu nome de usuário e não notaram o erro de digitação ao tentarem repetir a senha várias vezes, mas ainda acho que há maneiras de que isso possa ser valioso. Você pode até evitar alguns "falsos positivos" criando um filtro de bloom grande ou uma estrutura de dados semelhante com variantes de nomes de usuário válidos, nomes, sobrenomes, nomes de email etc. à medida que os usuários são adicionados.
R .. GitHub PARE DE AJUDAR O GELO
11

Se eu entendo o MO dos ataques de força bruta corretamente, um ou mais nomes de usuários são tentados continuamente.

Há duas sugestões que acho que ainda não vi aqui:

  • Eu sempre pensei que a prática padrão era ter um pequeno atraso (mais ou menos um segundo) após cada login errado para cada usuário. Isso impede a força bruta, mas não sei quanto tempo um atraso de um segundo manteria um ataque de dicionário à distância. (dicionário de 10.000 palavras == 10.000 segundos == cerca de 3 horas. Hmm. Não é bom o suficiente.)
  • em vez de uma desaceleração em todo o site, por que não um acelerador de nome de usuário. O acelerador se torna cada vez mais severo a cada tentativa errada (até um limite, eu acho, para que o usuário real ainda possa fazer login)

Editar : em resposta a comentários sobre um acelerador de nome de usuário: este é um acelerador específico de nome de usuário, independentemente da origem do ataque.

Se o nome de usuário for regulado, mesmo um ataque coordenado de nome de usuário (IP múltiplo, palpite único por IP, mesmo nome de usuário) será capturado. Os nomes de usuário individuais são protegidos pelo acelerador, mesmo que os atacantes estejam livres para tentar outro usuário / passe durante o tempo limite.

Do ponto de vista do invasor, durante o tempo limite, você poderá adivinhar pela primeira vez 100 senhas e descobrir rapidamente uma senha errada por conta. Você pode conseguir adivinhar apenas 50 segundos pelo mesmo período.

Do ponto de vista de uma conta de usuário, ainda é necessário o mesmo número médio de suposições para quebrar a senha, mesmo que as suposições sejam provenientes de várias fontes.

Para os invasores, na melhor das hipóteses, será o mesmo esforço para quebrar 100 contas como uma conta, mas como você não está otimizando em todo o site, pode acelerar o acelerador rapidamente.

Refinamentos extras:

  • detectar IPs que estão adivinhando várias contas - 408 Request Timeout
  • detectar IPs que estão adivinhando a mesma conta - 408 Tempo limite da solicitação após um grande número (digamos 100) de suposições.

Ideias de interface do usuário (podem não ser adequadas neste contexto), que também podem refinar o acima:

  • se você estiver no controle da configuração da senha, mostrar ao usuário a força da senha é incentivada a escolher uma melhor.
  • se você estiver no controle da página de login , após um pequeno (digamos 10) palpites de um único nome de usuário, ofereça um CAPTCHA.
jamesh
fonte
Um regulador de nome de usuário mais um regulador de IP é bom contra ataques de nome de usuário fixo ou IP fixo, e eles inviabilizam ataques tradicionais de dicionário. Mas se o atacante mudar constantemente os nomes de usuário, ele passará sem acionar o acelerador do nome de usuário. É isso que eu quero combater
Jens Roland
2
Obrigado pela edição, Jamesh. Agora estamos a falar. Adoro a idéia do 408. No entanto, mesmo com a restrição estrita de nome de usuário, uma botnet atacando vários usuários ainda funcionaria. E verificar as principais 5000 senhas contra um usuário é menos probabilidade de êxito do que verificar a senha top 1 em 5000 utilizadores
Jens Roland
Nada como o paradoxo do aniversário. Em um grupo grande, muitos usarão senhas inseguras e é provável que uma delas use qualquer popular. Também haverá um número razoável de pessoas como eu que não serão pegas por esse ataque.
David Thornley
2
Na verdade, talvez eu precise verificar novamente a matemática na minha declaração anterior. Depois de excluir as N senhas mais comuns, a probabilidade de o usuário ter a senha # (N + 1) pode aumentar o suficiente para equilibrar a diferença. Embora a curva é suficiente provavelmente íngreme para que isso não seja o caso
Jens Roland
9

Existem três fatores de autenticação:

  1. Um usuário sabe alguma coisa (ou seja, uma senha)
  2. Um usuário tem algo (isto é, um chaveiro)
  3. Um usuário é algo (ou seja, verificação de retina)

Geralmente, os sites aplicam apenas a política nº 1. Até a maioria dos bancos aplica apenas a política 1. Em vez disso, eles recorrem a uma abordagem "sabe outra coisa" para autenticação de dois fatores. (IE: um usuário sabe sua senha e o nome de solteira da mãe.) Se você puder, uma maneira de adicionar um segundo fator de autenticação não é muito difícil.

Se você pode gerar cerca de 256 caracteres aleatórios, você pode estruturá-lo em uma tabela 16 × 16 e pedir ao usuário para fornecer o valor na tabela da célula A-14, por exemplo. Quando um usuário se inscrever ou alterar sua senha, forneça a tabela e peça para imprimi-la e salvá-la.

A dificuldade dessa abordagem é que, quando um usuário esquece sua senha, como preferir, você não pode simplesmente oferecer o padrão "responda a essa pergunta e coloque uma nova senha", pois isso também é vulnerável à força bruta. Além disso, você não pode redefini-lo e enviar um novo por e-mail, pois o email também pode ser comprometido. (Consulte: Makeuseof.com e seu domínio roubado.)

Outra idéia (que envolve gatinhos) é o que a BOA chama SiteKey (acredito que eles tenham o nome registrado). Resumidamente, você solicita ao usuário que faça o upload de uma imagem ao se registrar e, quando tentarem fazer login, peça para escolher sua imagem dentre 8 ou 15 (ou mais) aleatórias. Portanto, se um usuário faz upload de uma foto do seu gatinho, teoricamente, apenas ele sabe exatamente qual é a imagem deles dentre todos os outros gatinhos (ou flores ou qualquer outra coisa). A única real remuneração que essa abordagem tem é o ataque do homem do meio.

Mais uma ideia (sem gatinhos) é rastrear os IPs com os quais os usuários acessam o sistema e exigir que eles executem autenticação adicional (captcha, escolha um gatinho, escolha uma chave nesta tabela) quando fizerem login em um endereço que não possuem. antes. Além disso, semelhante ao GMail, permite que o usuário visualize de onde efetuou login recentemente.

Editar, nova ideia:

Outra maneira de validar as tentativas de login é verificar se o usuário veio ou não da sua página de login. Você não pode verificar os referenciadores, pois eles podem ser facilmente falsificados. O que você precisa é definir uma chave na var _SESSION quando o usuário visualizar a página de logon e, em seguida, verifique se a chave existe ao enviar suas informações de logon. Se o bot não enviar a partir da página de login, ele não poderá efetuar o login. Você também pode facilitar isso envolvendo o javascript no processo, usando-o para definir um cookie ou adicionando algumas informações ao formulário após o carregamento. Ou você pode dividir o formulário em dois envios diferentes (ou seja, o usuário digita seu nome de usuário, envia e, em uma nova página, insere sua senha e envia novamente.)

A chave, neste caso, é o aspecto mais importante. Um método comum de gerá-los é uma combinação dos dados do usuário, seu IP e a hora em que foram enviados.

davethegr8
fonte
Tenho certeza de que há mais, mas se a idéia do SiteKey é exatamente o que você mencionou, um invasor não precisa ser um MITM, ele pode executar duas ou três tentativas de login para esse usuário e escolher a imagem que está repetindo entre os aleatórios. Mesmo se o conjunto de 8-15 fotos é estático para o usuário X,
Jens Roland
(continuação) ele provavelmente não seria muito difícil escolher o correto, já que as pessoas tendem a escolher os tipos previsíveis de imagens (mesmo as imagens de seus próprios álbuns do Flickr!)
Jens Roland
2
Sim, pensei no assunto que você falou ontem à noite depois que eu fui para casa. Eu acho que a maneira de corrigir isso é: quando um usuário efetuar login e fornecer uma senha correta, exiba sua imagem e alguns outros aleatórios. Quando eles não fornecer a senha correta, mostrar algum número de aleatório
davethegr8
1
imagens + 1, que podem ou não incluir sua própria imagem. Além disso, tive outra ideia, veja a edição no post. Mas sim, essas idéias são meio difíceis / complicadas.
davethegr8
1
Isso "poderia" funcionar, mas vejo alguns problemas. O que acontece se o proprietário da foto remover a imagem? Como você pode ter certeza de que as imagens retornadas não serão ofensivas para o usuário? Como um usuário se lembra onde clicou? (Parece difícil de esquecer)
davethegr8
7

Eu já havia respondido a uma pergunta muito semelhante em Como posso controlar as tentativas de login do usuário em PHP . Reiterarei a solução proposta aqui, pois acredito que muitos de vocês acharão informativo e útil ver algum código real. Lembre-se de que o uso de um CAPTCHA pode não ser a melhor solução devido aos algoritmos cada vez mais precisos usados ​​nos busters CAPTCHA atualmente:

Você não pode simplesmente impedir ataques de DoS encadeando a aceleração para um único IP ou nome de usuário. Inferno, você realmente não pode impedir tentativas de logon de disparo rápido usando esse método.

Por quê? Porque o ataque pode abranger vários IPs e contas de usuário, a fim de ignorar suas tentativas de limitação.

Vi em outro lugar que, idealmente, você deve rastrear todas as tentativas de login com falha no site e associá-las a um carimbo de data / hora, talvez:

CREATE TABLE failed_logins(
    id INT(11) UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
    username VARCHAR(16) NOT NULL,
    ip_address INT(11) UNSIGNED NOT NULL,
    attempted DATETIME NOT NULL
) engine=InnoDB charset=UTF8;

Decida sobre alguns atrasos com base no número geral de logins com falha em um determinado período de tempo. Você deve basear isso nos dados estatísticos retirados da sua failed_loginstabela, pois eles serão alterados com o tempo, com base no número de usuários e quantos deles poderão recuperar (e digitar) sua senha.


10 failed attempts = 1 second
20 failed attempts = 2 seconds
30 failed attempts = reCaptcha

Consulte a tabela em todas as tentativas de logon com falha para localizar o número de logins com falha por um determinado período, digamos 15 minutos:


SELECT COUNT(1) AS failed FROM failed_logins WHERE attempted > DATE_SUB(NOW(), INTERVAL 15 minute);

Se o número de tentativas durante o período especificado ultrapassar o seu limite, imponha a limitação ou force todos os usuários a usar um captcha (ou seja, reCaptcha) até que o número de tentativas com falha no período especificado seja menor que o limite.

// array of throttling
$throttle = array(10 => 1, 20 => 2, 30 => 'recaptcha');

// assume query result of $sql is stored in $row
$sql = 'SELECT MAX(attempted) AS attempted FROM failed_logins';
$latest_attempt = (int) date('U', strtotime($row['attempted']));
// get the number of failed attempts
$sql = 'SELECT COUNT(1) AS failed FROM failed_logins WHERE attempted > DATE_SUB(NOW(), INTERVAL 15 minute)';
// assume the number of failed attempts was stored in $failed_attempts
krsort($throttle);
foreach ($throttle as $attempts => $delay) {
    if ($failed_attempts > $attempts) {
        // we need to throttle based on delay
        if (is_numeric($delay)) {
            $remaining_delay = time() - $latest_attempt - $delay;
            // output remaining delay
            echo 'You must wait ' . $remaining_delay . ' seconds before your next login attempt';
        } else {
            // code to display recaptcha on login form goes here
        }
        break;
    }
}

O uso do reCaptcha em um determinado limite garantiria que um ataque de várias frentes fosse minimizado e os usuários normais do site não experimentariam um atraso significativo por tentativas legítimas de logon com falha. Não posso garantir a prevenção, pois já foi expandido que os CAPTCHA podem ser presos. Existem soluções alternativas, talvez uma variante de "Nomeie este animal", que poderia funcionar muito bem como um substituto.

Corey Ballou
fonte
6

Eu tenho que perguntar se você fez uma análise de custo-benefício desse problema; parece que você está tentando se proteger de um invasor com presença na web suficiente para adivinhar várias senhas, enviando talvez de 3 a 5 solicitações por IP (desde que você descartou a limitação de IP). Quanto (aproximadamente) esse tipo de ataque custaria? É mais caro que o valor das contas que você está tentando proteger? Quantas botnets gigantescas querem o que você tem?

A resposta pode ser não - mas, se for, espero que você esteja recebendo ajuda de algum profissional de segurança; a habilidade de programação (e a pontuação do StackOverflow) não se correlacionam fortemente com o conhecimento de segurança.

ojrac
fonte
(Quer dizer, se a resposta for 'não' -. Ou seja, que a despesa de um ataque botnet não é muito alto em relação às contas)
Jens Roland
Mas de qualquer maneira, você traz um ponto importante. Para meus próprios usos, não espero que nenhum operador de botnet se importe nem um pouco, mas estou liberando o código-fonte para qualquer pessoa que queira uma segurança decente para seu aplicativo da web e não sei o que os outros podem estar tentando proteger, ou quem são os seus inimigos
Jens Roland
Não estará guardando segredos nacionais, não importa o quê (os sistemas oficiais precisam de certificação especial, e tenho quase certeza de que nada baseado no PHP pode se qualificar), mas todos os aplicativos Web precisam de autenticação segura; portanto, se eu estiver divulgando isso, será d ser incrivelmente irresponsável não usar as melhores práticas sempre que posso
Jens Roland
1
Portanto, minha resposta curta é: estou construindo isso porque 99,9% dos sites e aplicativos por aí têm uma segurança terrível (mesmo nas grandes ligas: AOL, Twitter, Myspace já foram comprometidos antes) e, na maioria dos casos, porque são usando bibliotecas de autenticação de má qualidade.
Jens Roland
Leia também o artigo "To Catch A Predator", de Niels Provos et al. dos procedimentos USENIX de 2008 (link: usenix.org/events/sec08/tech/small.html ) É um revelador: 2 meses, um honeypot: 368.000 ataques de quase 30.000 IPs distintos, provenientes de mais de 5.600 botnets!
Jens Roland
5

Para resumir o esquema de Jens em um diagrama de transição de pseudo-estado / base de regra:

  1. usuário + senha -> entrada
  2. usuário +! senha -> negado
  3. usuário + IP_ conhecido (usuário) -> porta da frente, // never throttle
  4. usuário + IP desconhecido (usuário) -> catflap
  5. (#denied> n) via catflaps (site) -> acelerador catflaps (site) // slow the bots
  6. catflap + acelerador + senha + captcha -> entrada // humans still welcome
  7. catflap + throttle + password +! captcha -> negado // a correct guess from a bot

Observações:

  • Nunca estrangule a porta da frente. A polícia estatal elboniana tem o seu computador em sua casa, mas não pode interrogá-lo. A força bruta é uma abordagem viável do seu computador.
  • Se você fornecer um "Esquecer sua senha?" link, sua conta de email se torna parte da superfície de ataque.

Essas observações abrangem um tipo diferente de ataque aos que você está tentando combater.

jamesh
fonte
Absolutamente a conta de email faz parte da superfície de ataque. Eu tenho um conjunto de suposições de limite superior na segurança que minha estratégia fornecerá e o limite mais baixo é a segurança de email do próprio usuário. Se um invasor violar o e-mail de um usuário, todas as apostas serão desativadas.
Jens Roland
Além disso, acho que seu diagrama de transição de estado precisa de alguns detalhes: os parágrafos 3 e 4 devem incluir senha; Os nºs 1 e 2 devem incluir IP_conhecido (usuário), pois um login sempre tem um IP conhecido ou desconhecido; e # 6 é 'entrada apesar do acelerador'
Jens Roland
4

Parece que você está tentando se defender contra a força bruta distribuída lentamente . Não há muito o que você possa fazer sobre isso. Estamos usando um PKI e sem logins de senha. Isso ajuda, mas se seus clientes encontrarem estações de trabalho de vez em quando, isso não será muito aplicável.

Björn Raupach
fonte
Força bruta realmente rápida também. Eu esperava ser um pouco branda com a força bruta de usuário fixo (limitação de apenas 20 segundos), mas em um site com 50 mil usuários, isso tornaria possível a força bruta rápida de usuário variável (assumindo mais de 20 segundos para percorrer os usuários). E que, como eles dizem, seria um saco ..
Jens Roland
Força bruta bem rápida de um único host usa iptables ou qualquer firewall que você use.
Björn Raupach
Eu estava me referindo à força bruta rápida distribuída. É raro, mas é potencialmente muito desagradável
Jens Roland
3

Disclaimer: Eu trabalho para uma empresa de dois fatores, mas não estou aqui para ligá-lo. Aqui estão algumas observações.

Os cookies podem ser roubados com XSS e vulns do navegador. Os usuários geralmente alteram os navegadores ou limpam seus cookies.

Os endereços IP de origem são simultaneamente dinamicamente variáveis ​​e falsificáveis.

Captcha é útil, mas não autentica um ser humano específico.

Vários métodos podem ser combinados com sucesso, mas o bom gosto certamente está em ordem.

A complexidade da senha é boa, qualquer coisa baseada em senha depende criticamente de senhas com entropia suficiente. IMHO, uma senha forte anotada em um local físico seguro é melhor do que uma senha fraca na memória. As pessoas sabem como avaliar a segurança dos documentos em papel muito melhor do que sabem como calcular a entropia efetiva no nome de seus cães quando usadas como senha para três sites diferentes. Considere oferecer aos usuários a capacidade de imprimir uma página grande ou pequena cheia de códigos de uso único.

Questões de segurança como "qual era o seu mascote do ensino médio" são principalmente uma outra forma ruim de "algo que você conhece", a maioria delas é facilmente adivinhada ou direta no domínio público.

Como você observou, refrear as tentativas de logon com falha é um compromisso entre impedir ataques de força bruta e a facilidade de DoSing de uma conta. Políticas de bloqueio agressivas podem refletir uma falta de confiança na entropia de senha.

Pessoalmente, não vejo o benefício de impor a expiração de senha em um site de qualquer maneira. O invasor obtém sua senha uma vez. Ele pode alterá-la e obedecer a essa política da maneira mais fácil possível. Talvez um benefício seja que o usuário perceba mais cedo se o invasor alterar a senha da conta. Melhor ainda seria se o usuário fosse notificado de alguma forma antes do invasor obter acesso. Mensagens como "N tentativas com falha desde o último login" são úteis nesse sentido.

A melhor segurança vem de um segundo fator de autenticação que está fora de banda em relação ao primeiro. Como você disse, os tokens de hardware no "algo que você tem" são ótimos, mas muitos (nem todos) têm uma sobrecarga de administrador real associada à sua distribuição. Não conheço nenhuma solução biométrica "algo que você seja" que seja boa para sites. Algumas soluções de dois fatores funcionam com provedores abertos, outras possuem SDKs PHP / Perl / Python.

Marsh Ray
fonte
Todos os pontos excelentes - eu não poderia concordar mais. O ponto sobre insegurança de cookies é muito válido, mas sem um segundo fator de tokens físicos ou senhas únicas (distribuídas em uma linha segura), você realmente não pode proteger contra um endpoint vulnerável. Se a caixa / navegador do usuário estiver comprometida, o mesmo ocorrerá com os logins dele.
Jens Roland
1

Minha recomendação mais alta é simplesmente garantir que você mantenha os usuários informados sobre tentativas incorretas de login em suas contas - os usuários provavelmente levarão a força de sua senha muito mais a sério se forem apresentados com evidências de que alguém está realmente tentando acessar sua conta .

Na verdade, peguei alguém que invadiu a conta do myspace do meu irmão porque eles tentaram acessar a conta do Gmail que eu configurei para ele e usei o recurso 'redefinir minha senha por e-mail' ... que foi para a minha caixa de entrada.

nvuono
fonte
1
  1. Que tal exigir uma senha de uso único antes de inserir a senha normal? Isso tornaria muito óbvio que alguém estava atacando antes de ter muitas oportunidades de adivinhar a senha principal?

  2. Mantenha uma contagem / taxa global de falhas de login - este é o indicador de um ataque - durante um ataque, seja mais rigoroso quanto a falhas de login, por exemplo, bana IPs mais rapidamente.

Douglas Leeder
fonte
1) Como você implementaria uma senha descartável em uma linha não segura e não autenticada? Em outras palavras, quando o usuário define essas senhas únicas? 2) Sim, essa é a essência do # 4 da minha lista, o limite em todo o site para tentativas falhas. A desvantagem é a oportunidade de DoS que ele abre.
Jens Roland
0

Não acredito que haja uma resposta perfeita, mas estaria inclinado a abordá-la com base na tentativa de confundir os robôs se um ataque for detectado.

Em cima da minha mente:

Alterne para uma tela de login alternativa. Possui vários espaços em branco de nome de usuário e senha que realmente aparecem, mas apenas um deles está no lugar certo. Os nomes dos campos são ALEATÓRIOS - uma chave de sessão é enviada junto com a tela de login, e o servidor pode descobrir quais são os campos. Se você tiver êxito ou falhar, ele será descartado para que você não possa tentar um ataque de repetição - se você rejeitar a senha, eles obterão um novo ID de sessão.

Qualquer formulário enviado com dados em um campo errado é assumido como sendo de um robô - o logon falha, ponto final e esse IP é regulado. Verifique se os nomes dos campos aleatórios nunca correspondem aos nomes dos campos legítimos, para que alguém que use algo que se lembre de senhas não seja enganado.

Em seguida, que tal um tipo diferente de captcha: você tem uma série de perguntas que não causam problemas para um ser humano. No entanto, eles não são aleatórios. Quando o ataque começa, todos recebem a pergunta 1. Após uma hora, a pergunta 1 é descartada, para nunca mais ser usada novamente e todos recebem a pergunta 2 e assim por diante.

O invasor não pode tentar fazer o download do banco de dados para colocar em seu robô devido à natureza descartável das perguntas. Ele precisa enviar novas instruções para sua botnet dentro de uma hora para ter a capacidade de fazer qualquer coisa.

Loren Pechtel
fonte
A tela de login alternativa parece confundir os seres humanos mais do que máquinas, francamente. Obviamente, estamos assumindo que o invasor teria verificado nossas medidas de segurança com antecedência. Ele poderia facilmente ajustar o raspador para encontrar os campos corretamente posicionados.
Jens Roland
As perguntas de verificação humana já foram feitas antes e não são muito eficazes. Para um operador de botnet humano, responder uma pergunta por hora (após a qual a nova resposta seria propagada para os bots) durante um ataque seria bastante viável.
Jens Roland
Você está perdendo o objetivo. O atacante não pode verificar antecipadamente, porque mostra apenas as defesas extras quando um ataque aparece.
Loren Pechtel
Claro, o humano podia ver qual era a pergunta - mas ele tinha que comunicar isso a todos os seus bots. Esse é um caminho de comunicação que facilita a derrubada da botnet.
Loren Pechtel
Eu não acho que estou perdendo o objetivo. Não quero dizer que ele teria corrido um ataque anteriormente para verificar as nossas medidas de segurança, quero dizer que ele teria lido esta discussão e verificado o código (aberto) fonte para verificar se há weknesses :)
Jens Roland
0

Como várias pessoas incluíram o CAPTCHA como um mecanismo humano de fallback, estou adicionando uma pergunta anterior do StackOverflow e um tópico sobre a eficácia do CAPTCHA.

O reCaptcha foi quebrado / hackeado / OCR'd / derrotado / quebrado?

O uso do CAPTCHA não limita as melhorias de sua otimização e outras sugestões, mas acho que o número de respostas que incluem o CAPTCHA como substituto deve considerar os métodos baseados em humanos disponíveis para as pessoas que desejam violar a segurança.

Matthew Glidden
fonte
0

Você também pode acelerar com base na força da senha de um usuário.

Quando um usuário registra ou altera sua senha, você calcula uma classificação de força para sua senha, digamos entre 1 e 10.

Algo como "senha" marca 1, enquanto "c6eqapRepe7et * Awr @ ch" pode ter 9 ou 10 e quanto maior a pontuação, mais tempo leva para a aceleração entrar em ação.

Joseph W
fonte
2
Entendo a ideia, mas isso vazaria indiretamente informações sobre a senha, informando ao invasor se uma senha vale a pena invadir ou não. Isso pode parecer um pouco teórico, mas muitos usuários reutilizam senhas. Portanto, se eu quiser entrar no Strong_Throttling_Website.com, posso simplesmente atacar contas (privilegiadas) aleatoriamente até encontrar um usuário, 'Freddy', que tenha uma senha fraca (por exemplo, aceleração antecipada), vá para Less_Secure_Website.edu e faça um ataque fácil de dicionário na conta de Freddy lá. É um pouco envolvido, mas certamente praticável.
Jens Roland
0

A primeira resposta que geralmente ouvi ao fazer esta pergunta é alterar as portas, mas esqueça isso e desative o IPv4. Se você permitir apenas clientes de redes IPv6, não estará mais orando por uma simples varredura de rede e os atacantes recorrerão a pesquisas de DNS. Não execute no mesmo endereço do seu Apache (AAAA) / Sendmail (MX-> AAAA) / o que você deu a todos (AAAA). Verifique se a sua zona não pode ser xferd. Aguarde, você está permitindo que sua zona seja baixada por alguém?

Se os bots encontrarem o servidor configurando novos nomes de host, basta acrescentar algumas semelhanças aos nomes de host e alterar seu endereço. Deixe os nomes antigos e até os nomes de configuração ** honeypot para que a rede de bots atinja o tempo limite.

** Teste seus registros reversos (PTR) (em ip6.arpa.) Para ver se eles podem ser usados ​​para zerar os on / 4 que possuem registros VS / 4 que não. IE Normalmente, o ip6.arpa teria ~ 32 "." S em um endereço, mas tentar com os últimos desaparecidos pode iludir os blocos de rede que possuem registros VS outros que não. Se você levar isso adiante, é possível pular grandes porções do espaço de endereço.

Na pior das hipóteses, os usuários terão que configurar um túnel IPv6, não é como se tivessem que acessar VPN em uma DMZ ... Embora se pergunte por que essa não é a primeira opção.

O Kerberos também é legal, mas o IMHO LDAP explode (o que há de errado com o NISPlus? Li que a Sun decidiu que os usuários queriam LDAP e, por isso, abandonaram o NIS +). O Kerberos funciona bem sem LDAP ou NIS, apenas com o gerenciamento de usuários host por host. O uso do Kerberos fornece uma PKI fácil de usar, se não automatizada.

Mike Mestnik
fonte
0

Um pouco tarde aqui, mas eu estava pensando, assumindo um caso difícil - o invasor usa muitos IPs aleatórios, nomes de usuário aleatórios e uma senha aleatória selecionada dentre uma lista dos 10.000 mais populares.

Uma coisa que você pode fazer, especialmente se o sistema parecer estar sob ataque, pois há muitas tentativas erradas de senha no sistema e, especialmente, se a senha é de baixa entropia, é fazer uma pergunta secundária, como os nomes de seus pais, por exemplo . Se um invasor acertar um milhão de contas tentando a senha 'password1', há uma boa chance de obter muito, mas suas chances de acertar os nomes reduziriam drasticamente o sucesso.

Tim 333
fonte