BLOG | NGINX

Denylisting de IP dinâmico com NGINX Plus e fail2ban

NGINX-Parte-de-F5-horiz-preto-tipo-RGB
Miniatura de Liam Crilly
Liam Crilly
Publicado em 19 de setembro de 2017
Foto: Arnold Reinhold – Trabalho próprio, CC BY‑SA 3.0

Você pode não perceber, mas seu site está sob constante ameaça. Se estiver executando o WordPress, os bots estão tentando enviar spam para você. Se tiver uma página de login, haverá ataques de força bruta de senha. Você também pode considerar os spiders dos mecanismos de busca como visitantes indesejados.

Defender seu site de atividades indesejadas, suspeitas e maliciosas não é uma tarefa fácil. Firewalls de aplicativos da Web, como o NGINX App Protect e os módulos certificados NGINX Plus disponíveis em nossos parceiros, são ferramentas eficazes e devem ser considerados como parte de sua pilha de segurança. Para a maioria dos ambientes, segurança nunca é demais, e uma abordagem em várias camadas é invariavelmente a mais eficaz.

Nesta postagem do blog, discutiremos o uso do fail2ban como outra camada da pilha de segurança da web. Fail2ban é um sistema de detecção de intrusão (IDS) que monitora continuamente arquivos de log em busca de atividades suspeitas e, em seguida, executa uma ou mais ações pré-configuradas. Normalmente, o fail2ban monitora tentativas de login com falha e então bloqueia (bane) o endereço IP infrator por um período de tempo. Esta é uma defesa simples, porém eficaz, contra ataques de força bruta de senha.

No NGINX Plus R13, introduzimos um armazenamento de chave-valor nativo e uma nova API NGINX Plus. Isso permite uma riqueza de soluções de configuração dinâmica nas quais a configuração e o comportamento do NGINX Plus podem ser controlados por um sistema externo. Nesta postagem do blog, também mostraremos como o fail2ban pode ser usado para reconfigurar automaticamente o NGINX Plus para ignorar solicitações de endereços IP que causaram vários eventos de autenticação com falha.

Editor – No NGINX Plus R16 e posteriores, os armazenamentos de chave-valor podem ser sincronizados em todas as instâncias do NGINX Plus em um cluster. (O compartilhamento de estado em um cluster também está disponível para outros recursos do NGINX Plus.) Para obter detalhes, consulte nosso blog e o Guia de administração do NGINX Plus .

Usando um armazenamento de valor-chave para lista de bloqueio de IP

O armazenamento de chave-valor NGINX Plus é um armazenamento nativo na memória com três características principais:

  1. Os pares de chave-valor são representados como objetos JSON
  2. Os pares de chave-valor são gerenciados inteiramente por meio de uma API
  3. Os valores estão disponíveis para o NGINX Plus como variáveis de configuração regulares

O armazenamento de chave-valor é definido pela criação de uma zona de memória compartilhada nomeada pela diretiva keyval_zone . Este armazenamento de chave-valor pode então ser preenchido com um conjunto inicial de valores usando o método HTTP POST para enviar um objeto JSON para a API. A diretiva keyval então define qual variável existente será usada como a chave de pesquisa ( $remote_addr no exemplo), e o nome de uma nova variável ( $num_failures ) que será avaliada a partir do valor correspondente dessa chave.

Configuração e gerenciamento do armazenamento de chave-valor do NGINX Plus

A API é habilitada designando um bloco de localização como o ponto de extremidade da API NGINX Plus.


server {
listen 1111;
allow 127.0.0.1; # Permitir acesso somente do host local,
deny all; # e impedir acesso remoto.

location /api {
api write=on; # O ponto de extremidade da API do NGINX Plus no modo de leitura/gravação
}
}
keyval_zone zone=denylist:1M;
keyval $remote_addr $num_failures zone=denylist;

server {
listen 80;

location / {
root /usr/share/nginx/html;
if ($num_failures) {
return 403;
}
}
}

vim: syntax=nginx

Antes de adicionarmos pares de chave-valor a ele, uma solicitação do conteúdo do armazenamento da lista de bloqueios retorna um objeto JSON vazio.

$ curl http://localhost:1111/api/6/http/keyvals/denylist {}

O armazenamento de chave-valor agora pode ser preenchido com um par de chave-valor inicial usando o método HTTP POST (na forma do argumento -d para o comando curl ) para enviar um novo objeto JSON. Vários pares de chave-valor podem ser enviados por POST para um armazenamento de chave-valor vazio e, depois disso, individualmente.

$ curl -iX POST -d '{"10.0.0.1":"1"}' http://localhost:1111/api/6/http/keyvals/denylist HTTP/1.1 201 Criado ...

Um par chave-valor é removido aplicando PATCH na chave com um valor nulo .

$ curl -iX PATCH -d '{"10.0.0.1":null}' http://localhost:1111/api/6/http/keyvals/denylist HTTP/1.1 204 Nenhum conteúdo ...

Todos os pares de chave-valor podem ser removidos do armazenamento de chave-valor enviando o método DELETE .

$ curl -iX DELETE http://localhost:1111/api/6/http/keyvals/denylist HTTP/1.1 204 Nenhum conteúdo ...

Uma implementação simples de lista de negação de IP agora pode ser configurada.


server {
listen 1111;
allow 127.0.0.1; # Permitir acesso somente do host local,
deny all; # e impedir acesso remoto.

location /api {
api write=on; # O ponto de extremidade da API do NGINX Plus no modo de leitura/gravação
}
}
keyval_zone zone=denylist:1M;
keyval $remote_addr $num_failures zone=denylist;

server {
listen 80;

location / {
root /usr/share/nginx/html;
if ($num_failures) {
return 403;
}
}
}

vim: syntax=nginx

Este snippet de configuração configura a porta 80 como um servidor web. A linha 18 avalia a variável $num_failures para a parte do valor do par chave-valor na zona de memória compartilhada da lista de bloqueios que corresponde à chave que corresponde à variável $remote_addr (endereço IP do cliente). Este processo de avaliação de $num_failures é expresso mais claramente sequencialmente:

  1. Passe o valor de $remote_addr para o armazenamento de chave-valor da lista de bloqueio
  2. Se $remote_addr for uma correspondência exata para uma chave, obtenha o valor desse par chave-valor
  3. Retorna o valor como $num_failures

E assim, se o endereço IP do cliente foi PUBLICAR‑ed para o armazenamento de chave-valor, todas as solicitações resultarão em um HTTP 403 Proibido erro. A vantagem dessa abordagem, em oposição ao uso de um bloco de mapa para a mesma finalidade, é que a lista de bloqueio de IP pode ser controlada por um sistema externo.

Usando fail2ban para gerenciar dinamicamente a lista de bloqueio de IP

Como mencionado acima, o fail2ban é comumente usado para detectar atividades suspeitas e/ou maliciosas em arquivos de log e, então, tomar medidas para proteger o sistema. A ação padrão é configurar o iptables para descartar todos os pacotes originados do endereço IP que foi registrado. Essa abordagem, embora eficaz no bloqueio de um agente malicioso, proporciona uma experiência de usuário muito ruim para usuários genuínos, especialmente se eles esqueceram suas senhas. Para esses usuários, parece que o site está simplesmente indisponível.

A configuração a seguir descreve uma ação fail2ban que envia o endereço IP ofensivo ao armazenamento de chave-valor da lista de bloqueio do NGINX Plus. O NGINX Plus exibe uma página de erro mais útil e aplica simultaneamente um limite de taxa de solicitação a esse endereço IP para que, se as ações fizerem parte de um ataque, o ataque seja efetivamente neutralizado.

Assumimos uma instalação padrão do fail2ban no mesmo host do NGINX Plus, com toda a configuração no diretório /etc/fail2ban .

A ação fail2ban a seguir usa a API NGINX Plus para adicionar e remover endereços IP “banidos” dentro do armazenamento de chave-valor da lista de bloqueios da mesma forma que nosso exemplo simples acima. Colocamos o arquivo nginx-plus-denylist.conf no diretório /etc/fail2ban/action.d .


[Definição]
actionban = curl -s -o /dev/null -d '{"":""}' http://localhost:1111/api/6/http/keyvals/denylist
actionunban = curl -s -o /dev/null -X PATCH -d '{"":null}' http://localhost:1111/api/6/http/keyvals/denylist

A seguinte prisão fail2ban habilita o filtro integrado que detecta tentativas de login com falha usando o módulo de autenticação básica HTTP do NGINX e aplica a ação definida em nginx-plus-denylist.conf . Muitos outros filtros integrados estão disponíveis e podem ser facilmente criados para detectar atividades indesejadas nos logs de acesso do NGINX.


[PADRÃO]
bantime = 120
banaction = nginx-plus-denylist

[nginx-http-auth]
habilitado = true

O seguinte snippet de configuração do NGINX Plus aplica a autenticação HTTP Basic à página padrão “Bem-vindo ao NGINX”. Colocamos o arquivo password_site.conf no diretório /etc/nginx/conf.d .


server {
listen 1111;
allow 127.0.0.1; # Permitir acesso somente do host local,
deny all; # e impedir acesso remoto.

location /api {
api write=on; # O ponto de extremidade da API do NGINX Plus no modo de leitura/gravação
}
}

keyval_zone zone=denylist:1M state=denylist.json;
keyval $remote_addr $num_failures zone=denylist;

limit_req_zone $binary_remote_addr zone=20permin:10M rate=20r/m;

server {
listen 80;
root /usr/share/nginx/html;

location / {
auth_basic "site fechado";
auth_basic_user_file users.htpasswd;

se ($num_failures) {
reescrever ^.* /banned.html;
}
}

localização = /banned.html {
limite_req zona=20permin burst=100;
}
}

vim: sintaxe=nginx

A linha 11 define o keyval_zone como em denylist_keyval.conf acima, mas com a adição do parâmetro state , que especifica um arquivo onde o estado do armazenamento de chave-valor é armazenado e, portanto, persiste quando o NGINX Plus é interrompido e reiniciado. O armazenamento de chave-valor persiste em recargas de configuração regulares sem especificar um arquivo de estado. (As linhas 1 a 10 não são mostradas, mas são as mesmas de denylist_keyval.conf .)

A linha 14 cria uma zona de memória compartilhada chamada 20permin e especifica uma taxa máxima de solicitação de 20 solicitações por minuto para cada endereço IP do cliente. Esse limite de taxa é então aplicado quando um endereço IP é adicionado à lista de bloqueio pelo fail2ban (linha 30).

O bloco do servidor define um servidor web escutando na porta padrão (80), onde todas as solicitações são correspondidas pelo local / bloco (linha 20). A diretiva root (linha 18) especifica onde nosso conteúdo web reside. As linhas 21–22 especificam que a autenticação HTTP Basic é necessária para este site e que o banco de dados de senhas para usuários autorizados está no arquivo users.htpasswd . A documentação da diretiva auth_basic_user_file descreve o formato desse arquivo. Observe que esta configuração não é criptografada para fins de teste e qualquer site de produção que use autenticação HTTP Basic deve usar SSL/TLS para segurança de transporte.

Quando o endereço IP do cliente foi colocado na lista de negação (linhas 24–26), em vez de retornar o HTTP403 código de erro, reescrevemos a solicitação para /banned.html , que é então processada no bloco de localização que corresponde exatamente ao URI (linha 29). Isso retorna uma página da web estática que explica que o endereço IP do usuário foi bloqueado devido a falhas excessivas de login. Ele também aplica um limite de taxa restritivo (linha 30) que impede que um cliente malicioso consuma recursos do sistema desnecessariamente.

Página que os usuários veem quando seu endereço IP é negado

(O HTML para esta página da web de exemplo está disponível como banned.html no repositório GitHub para esta postagem.)

Podemos simular sucessivas tentativas de login com falha e a atividade fail2ban correspondente da seguinte maneira.

$ curl -i http://admin:senha@www.exemplo.com/HTTP/1.1 401 Não autorizado ...
$ curl -i http://admin:admin@www.example.com/
HTTP/1.1 401 Não autorizado ...
$ curl -i http://admin:pass1234@www.example.com/
HTTP/1.1 401 Não autorizado ...
$ curl -i http://admin:letmein@www.example.com/
HTTP/1.1 401 Não autorizado ...
$ curl -i http://admin:fred@www.example.com/
HTTP/1.1 401 Não autorizado ...
$ enrolar http://admin:P@ssw0rd@www.example.com/
<!DOCTYPE html>
<html>
<cabeçalho>
<título>Banido</título>
...
$ cauda -f /var/log/fail2ban.log
2017-09-15 13:55:18,903 fail2ban.filter [28498]: INFO [nginx-http-auth] Encontrado 172.16.52.1 2017-09-15 13:55:28,836 fail2ban.filter [28498]: INFO [nginx-http-auth] Encontrado 172.16.52.1 2017-09-15 13:57:49,228 fail2ban.filter [28498]: INFO [nginx-http-auth] Encontrado 172.16.52.1 2017-09-15 13:57:50,286 fail2ban.filter [28498]: INFO [nginx-http-auth] Encontrado 172.16.52.1 2017-09-15 13:57:52,015 fail2ban.filter [28498]: INFO [nginx-http-auth] Encontrado 172.16.52.1 2017-09-15 13:57:52,088 fail2ban.actions [28498]: AVISO [nginx-http-auth] Ban 172.16.52.1 2017-09-15 13:59:52,379 fail2ban.actions [28498]: AVISO [nginx-http-auth] Desbanir 172.16.52.1

Esta solução dinâmica de lista de bloqueio de IP agora pode ser executada sem nenhuma alteração adicional na configuração. O Fail2ban observa os arquivos de log do NGINX e adiciona endereços IP banidos ao armazenamento de chave-valor do NGINX Plus usando a API. Após 120 segundos (o bantime configurado em jail.local ), o endereço IP ofensivo é removido da denylist, novamente usando a API do NGINX Plus, e as tentativas de login são mais uma vez aceitas desse endereço.

A API NGINX Plus e o armazenamento de chave-valor tornam esse tipo de integração possível. Soluções de configuração avançadas agora podem ser obtidas sem exigir a construção de arquivos de configuração do NGINX Plus e a execução de recarregamentos. Gostaríamos de saber como você está usando esses recursos para criar suas próprias soluções de configuração dinâmica. Por favor, adicione um comentário abaixo.

Para experimentar o NGINX Plus, comece hoje mesmo seu teste gratuito de 30 dias ou entre em contato conosco para discutir seus casos de uso.


"Esta postagem do blog pode fazer referência a produtos que não estão mais disponíveis e/ou não têm mais suporte. Para obter as informações mais atualizadas sobre os produtos e soluções F5 NGINX disponíveis, explore nossa família de produtos NGINX . O NGINX agora faz parte do F5. Todos os links anteriores do NGINX.com redirecionarão para conteúdo semelhante do NGINX no F5.com."