Ataques da camada 7 em sites incluem ataques na camada do servidor web (nginx, apache, etc.) e ataques na camada do servidor de aplicativos (php-fpm, nodejs, etc.), que geralmente está localizado atrás do servidor proxy (nginx, apache , etc.). De uma perspectiva de protocolo de rede, ambos são ataques à camada de aplicativo. Mas nós, do ponto de vista prático, precisamos separar esses dois casos. O servidor web (nginx, apache, etc.), como regra, fornece independentemente arquivos estáticos (imagens, estilos, scripts) e solicitações de proxies para conteúdo dinâmico para o servidor de aplicativos (php-fpm, nodejs, etc.)). São essas solicitações que se tornam alvos de ataques, já que, ao contrário das solicitações estáticas, os servidores de aplicativos, ao gerar conteúdo dinâmico, requerem várias ordens de magnitude de recursos do sistema mais limitados, que é o que os invasores usam.
Por mais banal que pareça, para se defender contra um ataque, ele deve primeiro ser identificado. Na verdade, não apenas os ataques DDoS podem levar à falha do site, mas também outros motivos associados a erros de desenvolvedores e administradores de sistema. Para a conveniência da análise, você precisa adicionar o parâmetro $ request_time ao formato de log nginx (desculpe, não tenho uma opção com o apache) e registrar as solicitações para o servidor de aplicativos em um arquivo separado:
log_format timed '$remote_addr - $remote_user [$time_local] '
'$host:$server_port "$request" $status $body_bytes_sent '
'"$http_referer" "$http_user_agent" ($request_time s.)';
location /api/ {
proxy_pass http://127.0.0.1:3000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-NginX-Proxy true;
access_log /var/log/ngunx/application_access.log timed;
}
Tendo recebido logs para o servidor de aplicação em um arquivo separado (sem logs estáticos) e com o tempo de solicitação em segundos, você pode identificar rapidamente o momento em que o ataque começa, quando o número de solicitações e o tempo de resposta começam a aumentar drasticamente.
Tendo identificado o ataque, você pode prosseguir para a defesa.
Muitas vezes, os administradores de sistema tentam proteger o site, limitando o número de solicitações de um único endereço IP. Para fazer isso, use 1) a diretiva nginx limit_req_zone ( consulte a documentação ), 2) fail2ban e 3) iptables. Claro, esses métodos devem ser usados. No entanto, esse método de proteção foi ineficaz por até 10-15 anos. Há duas razões para isso:
1) O tráfego gerado pela rede de bots durante um ataque no 7º nível pode ser menor em volume do que o tráfego de um visitante comum do site, uma vez que um visitante comum do site tem uma solicitação "pesada" para o servidor de aplicativos (php-fpm , nodejs, etc.) existem cerca de 100 solicitações "leves" para baixar arquivos estáticos que são enviados pelo servidor da web (nginx, apache, etc.). O Iptables não oferece proteção contra essas solicitações, pois pode restringir o tráfego apenas por indicadores quantitativos e não leva em consideração a separação das solicitações em estática e dinâmica.
2) O segundo motivo é a distribuição da rede de bots (a primeira letra é D na abreviatura DDoS). O ataque geralmente envolve uma rede de vários milhares de bots. Eles são capazes de fazer solicitações com menos frequência do que o usuário médio. Como regra, ao atacar um site, um invasor calcula empiricamente os parâmetros limit_req_zone e fail2ban. E configura a rede do bot para que essa proteção não funcione. Freqüentemente, os administradores de sistema começam a subestimar esses parâmetros, desabilitando clientes reais, mas sem muito resultado em termos de proteção contra bots.
Para proteger com sucesso um site de DDoS, é necessário que todos os meios de proteção possíveis sejam usados no servidor do complexo. Em minha postagem anterior sobre este tópico, proteção DDoS no nível do servidor webexistem links para materiais sobre como configurar iptables, e quais parâmetros do kernel do sistema precisam ser ajustados para o valor ideal (significando, em primeiro lugar, o número de arquivos abertos e sockets). Este é um pré-requisito, necessário, mas não uma condição suficiente para proteção contra bots.
Além disso, é necessário construir uma proteção baseada na detecção de bots. Tudo o que é necessário para entender a mecânica de detecção de bots foi descrito em detalhes no artigo histórico sobre Habré O módulo nginx para combater DDoS pelo autor kyprizel e está implementado na biblioteca do mesmo autor testcookie-nginx-module
É uma biblioteca C e continua a ser desenvolvida por uma pequena comunidade de autores. Provavelmente, nem todos os administradores de sistema estão prontos para compilar uma biblioteca desconhecida em um servidor de produção. Se você precisar fazer alterações adicionais no trabalho da biblioteca, isso está completamente além do escopo de um administrador de sistema ou desenvolvedor comum. Felizmente, agora existem novos recursos: a linguagem de script Lua que pode ser executada no servidor nginx. Existem duas compilações populares do nginx com um mecanismo de script Lua integrado: openresty, que foi originalmente inspirado no Taobao, depois em Cloudfare, e nginx-extras, que está incluído em algumas distribuições do Linux, como o Ubuntu. Ambas as opções usam as mesmas bibliotecas, então não faz muita diferença qual usar.
A proteção de bot pode ser baseada na determinação da capacidade do cliente da web de 1) executar código JavaScript, 2) fazer redirecionamentos e 3) definir cookies. De todos esses métodos, a execução do código JavaScript acabou sendo o menos promissor, e eu recusei, uma vez que o código JavaScript não é executado se o conteúdo for carregado com solicitações de plano de fundo (ajax), e recarregar a página usando JavaScript distorce o estatísticas de transições para o site (desde o título Referer). Assim, existem redirecionamentos que configuram cookies, cujos valores estão sujeitos a lógicas que não podem ser reproduzidas no cliente, e não permitem que clientes acessem o site sem esses cookies.
Em meu trabalho, contei com a biblioteca leeyiw / ngx_lua_anticc, que atualmente não está sendo desenvolvido, e continuei as melhorias em meu fork apapacy / ngx_lua_anticc , já que o trabalho da biblioteca original não se adequava a tudo.
Para operar os contadores de consulta na biblioteca, são usadas tabelas de memória, que oferecem suporte a métodos incr, convenientes para incrementar os valores dos contadores e definir os valores com TTL. Por exemplo, o fragmento de código a seguir incrementa a contagem de solicitações de um único endereço IP se o cliente não tiver um cookie com um nome específico definido. Se o contador ainda não foi inicializado, ele é inicializado em 1 com um TTL de 60 segundos. Após ultrapassar o número de solicitações 256 (em 60 segundos), o cliente não tem permissão para acessar o site:
local anticc = ngx.shared.nla_anticc
local remote_id = ngx.var.remote_addr
if not cookies[config.cookie_name] then
local count, err = anticc:incr(remote_id, 1)
if not count then
anticc:set(remote_id, 1, 60)
count = 1
end
if count >= 256 then
if count == 256 then
ngx.log(ngx.WARN, "client banned by remote address")
end
ngx.exit(444)
return
end
end
Nem todos os bots são prejudiciais. Por exemplo, você precisa ignorar os bots de pesquisa e os bots de sistemas de pagamento que relatam mudanças nos status de pagamento para o site. É bom se você puder criar uma lista de todos os endereços IP dos quais essas solicitações podem vir. Nesse caso, você pode criar uma lista "branca":
local whitelist = ngx.shared.nla_whitelist
in_whitelist = whitelist:get(ngx.var.remote_addr)
if in_whitelist then
return
end
Mas nem sempre isso é possível. Um dos problemas é a incerteza com os endereços dos bots do Google. Ignorar todos os bots que falsificam os bots do Google é o mesmo que remover a proteção do site. Portanto, usaremos o módulo resty.exec para executar o comando do host:
local exec = require 'resty.exec'
if ngx.re.find(headers["User-Agent"],config.google_bots , "ioj") then
local prog = exec.new('/tmp/exec.sock')
prog.argv = { 'host', ngx.var.remote_addr }
local res, err = prog()
if res and ngx.re.find(res.stdout, "google") then
ngx.log(ngx.WARN, "ip " .. ngx.var.remote_addr .. " from " .. res.stdout .. " added to whitelist")
whitelist:add(ngx.var.remote_addr, true)
return
end
if res then
ngx.log(ngx.WARN, "ip " .. ngx.var.remote_addr .. " from " .. res.stdout .. "not added to whitelist")
else
ngx.log(ngx.WARN, "lua-resty-exec error: " .. err)
end
end
A experiência mostra que essa estratégia de proteção permite que você proteja o site de uma determinada classe de ataques, que costumam ser usados para fins de concorrência desleal. Compreender os mecanismos de ataques e métodos de proteção ajuda a economizar muito tempo em tentativas malsucedidas de defesa contra fail2ban e, ao usar proteção de terceiros (por exemplo, da Cloudfare), escolha os parâmetros de proteção mais deliberadamente.
apapacy@gmail.com
9 de maio de 2021