- Sem usar CDN, o texto organiza formas de bloquear a maioria dos bots com implementação ou configuração ruim combinando protocolo HTTP/faixas de IP/sinais do cliente/características TCP/impressão digital TLS/compressão de conteúdo
- Todos os métodos devem ser ajustados de forma seletiva e, sem antes analisar 1 a 3 anos de logs de acesso, você pode acabar bloqueando junto usuários de VPN/motores de busca/CDN/escolas/bibliotecas/usuários de determinados idiomas
- Bloquear clientes HTTP/1.1 e faixas AS/CIDR de datacenters pode remover muitos bots, mas também pode excluir motores de busca, incluindo o GoogleBot, e usuários legítimos de datacenters
- A inspeção de cabeçalhos no Nginx e os filtros de tamanho de janela TCP/MSS/TTL no nftables reduzem crawlers e scanners simples, mas podem gerar falsos positivos em ambientes normais como LTE/VPN/Windows
- Como alternativa de longo prazo, o texto propõe detecção de impressão digital TLS JA4 e respostas exclusivas em Brotli, mas alerta que isso não garante bloqueio completo e não deve ser usado em serviços com receita
Escopo do bloqueio e premissas de aplicação
- Primeiro é preciso decidir se o objetivo é bloquear alguns bots, a maioria dos bots ou todos os bots
- O foco das abordagens tratadas aqui não é todo tipo de ferramenta de automação sofisticada, e sim bloquear de forma relativamente simples a maioria dos bots com implementação ou configuração ruim
- Para cada método, também é indicado o risco de bloquear usuários legítimos e motores de busca
- Depois de ser compartilhado no Hacker News em 26 de julho de 2026, o autor decidiu mover a maior parte dos recursos de bloqueio do blog para um site de demonstração separado, transformando-o em um tipo de quebra-cabeça em que o leitor lê o método e depois tenta acessar por conta própria
- Todas as configurações podem ser alteradas opcionalmente ou omitidas, e é necessário investigar e testar bastante antes de aplicar em produção
- Como usuários legítimos/sistemas internos da organização/serviços externos dos quais se depende podem ser bloqueados, a responsabilidade pela aplicação é inteiramente do operador
- Não usar em ambientes operacionais que gerem receita
Método 1: diferenciar pelo protocolo HTTP
- O risco de bloquear usuários legítimos é baixo, e o risco de bloquear alguns motores de busca é médio
- A ideia é explorar a diferença de que navegadores comuns usam HTTP/2.0, enquanto muitos bots usam HTTP/1.1
- Considera-se que o GoogleBot usa HTTP/1.1 e, por esse método, será bloqueado
- Os crawlers do Bing e do Facebook usam HTTP/2.0
- Serviços que buscam títulos de links ou prévias curtas via HTTP/1.1 também podem ser bloqueados
- O Opera Mini também fica excluído
- No Nginx, configure para redirecionar para outra página ou retornar
200, 403 ou 444 se $server_protocol não for HTTP/2.0
if ($server_protocol != HTTP/2.0) {
return 403 'Upgrade your client';
}
- Retornar
444 permite encerrar a conexão sem resposta separada
- Cada organização deve avaliar por conta própria se o benefício obtido compensa a perda causada por bloquear tráfego vindo da busca do Google
Método 2: bloquear faixas de IP de datacenters
- O risco de bloquear usuários domésticos/LTE legítimos é baixo, mas é médio para usuários de VPN e alto para motores de busca que operam em datacenters
- Nos logs de acesso dos últimos 1 a 2 anos, identifique requisições suspeitas combinando os seguintes sinais
- Protocolo HTTP
- User-Agent
Accept-Language
Sec-Fetch-Mode
Accept
- Consulte os IPs suspeitos em BGP Tools ou Hurricane Electric BGP Toolkit para verificar o AS ao qual pertencem e os Prefixes anunciados
- A lista de blackholes de rede fornecida pode incluir faixas de CDN e motores de busca, então deve ser aplicada de forma seletiva
- Antes de listas separadas, já se usa uma configuração que coloca em blackhole as faixas
3/8, 10/8, 11/8, 25/8, 26/8, 38/8, 41/8, 60/8, 61/8, 200/8, 224/3
- Depois de copiar a página de Prefixes do AS, usa-se uma função de shell para extrair apenas os CIDRs, ordenar, remover duplicatas e consolidar
- Usa-se sum_cidr.pl, e o módulo Perl
Net::CIDR::Lite é necessário
- Após revisão, o resultado gerado é movido para arquivos
/usr/local/etc/*.netset
- Na inicialização do servidor, cada CIDR é adicionado como rota blackhole
for CflIP in $(grep -E ^[1-9] /usr/local/etc/_cloudflare.netset); do
/sbin/ip route add blackhole "${CflIP}" 2>/dev/null
done
- No exemplo, toda a faixa da Cloudflare é bloqueada para não aceitar requisições via Workers etc.
- O método de roteamento é escolhido porque o roteamento blackhole do Linux usa menos CPU do que regras
ipset do firewall
- Também é possível bloquear as faixas da empresa de hospedagem à qual o servidor atual pertence
- DNS/configuração/serviços internos não devem usar o mesmo espaço de endereços
- Rotas de gateway diretamente conectadas têm prioridade sobre rotas blackhole
Método 3: bloquear país/proxy/Tor/IP malicioso
- Baixe listas do repositório FireHOL Blocklists e adicione as faixas necessárias como rotas blackhole
- Como os arquivos de lista incluem comentários, é preciso removê-los com
grep -Ev '^#' antes de processar
- Em especial, recomendam-se as listas a seguir
firehol_abusers_30d.netset
firehol_level2.netset
- Listas grandes podem aumentar bastante o tempo de execução do script de inicialização
- Também são fornecidos os arquivos de configuração usados no servidor e no firewall reais
Método 4: inspecionar sinais do cliente HTTP
- Parte-se da premissa de que User-Agent e cabeçalhos podem ser falsificados, mas bots simples que priorizam velocidade muitas vezes não os falsificam corretamente
- Para requisições de
Curl e Wget, retorna-se texto simples; para requisições que contenham Bot, GPT, LLM, Spider, retorna-se 410 Gone
if ($http_user_agent ~* Curl) { return 200 '\nGNU Terry Pratchett\n\n'; }
if ($http_user_agent ~* Wget) { return 200 '\nGNU Terry Pratchett\n\n'; }
if ($http_user_agent ~* Bot) { return 410 '1000101'; }
if ($http_user_agent ~* GPT) { return 410 '1000101'; }
if ($http_user_agent ~* LLM) { return 410 '1000101'; }
if ($http_user_agent ~* Spider) { return 410 '1000101'; }
- Parte das strings observadas em User-Agent é verificada com uma única regex longa para bloquear crawlers/scanners/ferramentas de coleta
- Inclui substrings como
Go-http, Java, libwww, okhttp, urllib, python, nmap, zgrab, semrush, shodan, rss, scrap, crawler, headless, github, facebook, google, bing
- Antes de aplicar, é preciso agregar 2 a 3 anos de User-Agents e verificar se clientes legítimos reais batem na regex
sort access-user-agents.txt | uniq -c | sort
- Se a requisição correspondente for HTTP/1.1, ela é tratada como tendo alta probabilidade de ser bot, com exceção considerada para o GoogleBot
- Se for uma requisição HTTP/2.0, a filiação do IP é verificada adicionalmente com ferramentas BGP
Sec-Fetch-Mode
- Adicione
Sec-Fetch-Mode ao log de acesso e bloqueie se o valor não for um entre cors, no-cors, navigate
if ($http_sec_fetch_mode !~ (cors|no-cors|navigate)) {
return 410 '1000101';
}
Verificação de Referer
- Para impedir requisições que incorporam conteúdo ou fazem varredura a partir de outros sites, bloqueie quando
Referer contiver determinadas strings
- São verificados termos ligados a páginas de administração/motores de busca/redes sociais/criptomoedas/conteúdo adulto/scanners/WordPress etc.
- Um tipo específico de bot que alega ter
https://www.google.com/ como Referer também é bloqueado separadamente
- É um padrão observado em requisições que fingem ser Android antigo
Restrição de métodos HTTP
- Permita apenas
GET e POST, necessários para requisições normais de navegador, e bloqueie os demais métodos
if ($request_method !~ (^GET$|^POST)) {
return 410 '1000101';
}
- Dependendo da aplicação real, os caminhos que precisam de
POST podem ser restringidos com mais detalhe ou totalmente excluídos se não forem usados
Verificação de proxy e aparência de navegador
- Se houver cabeçalho
X-Forwarded-For, considera-se que a requisição veio de proxy e ela é bloqueada
- Ambientes legítimos de proxy compartilhado, como escolas ou bibliotecas, também podem acabar bloqueados
- Se o User-Agent não contiver nenhum entre
Linux, BSD, Macintosh, Windows, Mozilla, WhatsApp, considera-se que a requisição não se parece com navegador
- Também se usa uma regra que bloqueia quando
Accept-Language não contém en ou es
- Há grande chance de bloquear alguns navegadores e usuários legítimos que não usam inglês ou espanhol
- Também é apresentada uma regra opcional que bloqueia separadamente configurações de idioma contendo
br ou sy
Bloqueio de varredura em caminhos sensíveis
- Se forem requisitados os arquivos ou caminhos abaixo, isso é tratado como varredura automática e bloqueado
Método 5: bloquear scanners TCP com nftables
- As características dos pacotes TCP SYN são inspecionadas na chain
PREROUTING da tabela raw do nftables
- O endereço de servidor de exemplo
172.238.221.88 é especificado como destino para reduzir falsos positivos que podem ocorrer em situações de perda de pacotes
- Entre os pacotes SYN que chegam às portas 80/443, são bloqueados os que atendem às seguintes condições
- Tamanho da janela TCP menor que 12.288 bytes
- MSS fora da faixa de 1.220 a 1.460
- O critério usado é que clientes reais usam janelas maiores, e MSS fora dessa faixa tem baixa probabilidade de vir de cliente legítimo
- Restringir o MSS exatamente a
1460 torna a regra mais rígida, mas pode bloquear a maioria dos usuários de LTE e VPN
Restrição opcional baseada em TTL
- Se o TTL do TCP SYN for maior que
128, a maioria dos dispositivos LTE pode ser bloqueada
- Se o TTL for maior que
64, a maioria dos sistemas Windows também será bloqueada
- Os valores base de TTL são explicados assim
- Linux/Mac/BSD:
64
- Windows:
128
- LTE: valores maiores que esses
Exclusão do rastreamento de conexão
- Define-se
notrack para as portas 80/443 para não colocar o tráfego web na tabela conntrack
- Nesse caso, é preciso configurar diretamente regras sem estado para direção de envio e recebimento também na tabela filter
- No exemplo, permite-se tráfego entre portas de origem do cliente
1000-65535 e as portas 80/443 do servidor
Método 6: conteúdo adulto e cabeçalhos para robôs
- Para restringir acesso a conteúdo adulto, usa-se o cabeçalho RTA: Restricted To Adults
- Considera-se que métodos de verificação de idade além do RTA servem para rastreamento de usuários e monetização
- Os seguintes cabeçalhos são sempre adicionados às respostas do Nginx
add_header Rating 'RTA-5042-1996-1400-1577-RTA' always;
add_header adult 'porn, sex, politics, religion, philosophy' always;
add_header X-Robots-Tag "none,noindex,nofollow,nosnippet,noai" always;
- Bots comuns podem ignorar esses cabeçalhos, mas isso pode afetar motores de busca ou bots projetados para evitar conteúdo adulto
Método 7: detecção de impressão digital TLS
- Os métodos 1 a 6 acima são todos heurísticas grosseiras, e no longo prazo a análise de impressão digital TLS pode ser uma escolha melhor
- O JA4 pode ser usado sob a condição de que o bot não altere sua impressão digital TLS para ficar idêntica à de um navegador normal
- Primeiro, recomenda-se verificar o método de implantação em Deploying JA4 e depois aplicar o FoxIO JA4
Método 8: servir apenas conteúdo comprimido com Brotli
- O conteúdo do site é previamente comprimido com Brotli, e o servidor web é configurado para retornar apenas arquivos comprimidos
- A ideia é aproveitar o fato de que muitos bots não conseguem interpretar HTML comprimido com Brotli
- Após a aplicação, confirmou-se que vários bots deixaram de seguir links da página, indicando que não conseguiam de fato fazer parse do HTML
- No Nginx, configura-se para sempre servir arquivos Brotli estáticos
brotli_static always;
- Os arquivos HTML são pré-comprimidos assim
cat ./i.html | brotli --best -fncv > ./i.html.br
Método 9: induzir scanners a se autoidentificarem
- Um método separado para reduzir atacantes iniciantes e scanners que repetidamente exploram caminhos de vulnerabilidade é tratado em Help Attackers Self Report
1 comentários
Opiniões no Hacker News
Como alguém que opera vários sites públicos e também raspa outros sites para usar em ferramentas, fico me perguntando por que as pessoas se preocupam tanto com bots.
Até um WordPress com cache consegue lidar com cerca de 1.000 requisições por segundo no VPS mais barato, e um site estático bem feito provavelmente aguentaria 10 vezes isso. Fico curioso se estão servindo blogs com algo como Lambda, ou se é obsessão, defesa contra vulnerabilidades, ou um hábito da época em que crawlers realmente afetavam serviços em produção.
Os repositórios são open source, então os mantenho públicos de propósito. Hoje me defendo com uma verificação simples de cookies, que só deixa passar alguns poucos bots, mas é um compromisso que sacrifica a exposição em mecanismos de busca.
A ideia é mostrar métodos aplicáveis a fóruns, imageboards, servidores de chat etc., e todas as opções podem ser ajustadas ou desligadas. Antes de aplicar de verdade, é preciso validar em um servidor de teste; e tudo bem também só rir disso e seguir em frente.
Não é o fim do mundo levar alguns segundos a mais para verificar um servidor IMAP local porque a DMZ ficou travada, mas isso também não significa que eu tenha que gostar ou continuar permitindo.
No fim de semana, encerrei interfaces web viewvc (CVS/Subversion) e hgweb (Mercurial) que eu operava havia 10 a 20 anos. De IPs de proxies residenciais vinham 2,7 milhões de requisições por dia, em média 30 por segundo, sobrecarregando programas uWSGI/CGI antigos e outros sites no mesmo servidor, e o tráfego também estava se aproximando do limite do VPS, de 1 TB por mês.
Como as combinações dinâmicas de URLs de VCS podem chegar a milhões, o efeito do cache também era incerto; e não valia a pena gastar tempo ajustando ainda mais o servidor. No fim, escolhi dar mais um passo rumo a uma internet centralizada.
Bloquear tudo exceto agentes de usuário “aprovados” ajuda o monopólio dos navegadores existente e acelera a distopia. É exatamente esse tipo de problema que RMS vem alertando há décadas.
Se há um problema, o bloqueio deveria se basear no volume de tráfego e na frequência das requisições. Eu também não consigo acessar o site, mas não pretendo mudar meu comportamento por causa disso; como no DRM, adversários determinados acabarão passando.
Dito isso, independentemente da alegação de que qualquer navegador pode ser usado, é preciso ter especial cuidado com navegadores gerados de improviso ou que não foram suficientemente testados contra sites maliciosos. Aplicativos leitores também podem ser vulneráveis a servidores maliciosos se não tiverem passado por uma revisão ampla de código de terceiros feita por especialistas em testes de intrusão.
Gosto da ideia de adicionar um subdomínio cpanel falso apontando para
169.254.169.254, fazendo atacantes iniciantes escanearem as portas do próprio provedor de hospedagem e, assim, serem detectados ou bloqueados.Embora os IPs de origem estivessem espalhados pelo mundo, o ruído real de varredura vinha de uma única pessoa.
Bloqueio baseado em IP exige cuidado. Faixas de IP às vezes são realocadas, então você pode acabar bloqueando a pessoa errada; já vi várias vezes faixas que tinham sido bloqueadas por serem de uma região ou data center passarem para um ISP residencial
Bloquear HTTP/1.1 também traz um grande risco de impedir usuários reais que usam navegadores antigos. Além disso, há navegadores que não enviam a URL completa em requisições cross-origin; se o tráfego vier da Busca do Google, o referer pode apontar apenas para a página raiz do Google. Portanto, se você concluir que isso é uma mentira de bot e bloquear, pode acabar perdendo também o tráfego vindo da Busca do Google
Por outro lado, acho razoável bloquear HTTP/1.1. Faz mais de 10 anos que praticamente todos os navegadores suportam protocolos além dele, e, se o navegador é antigo a esse ponto, a maior parte da Web dominante já deve quebrar nele; então mais um site pessoal não funcionar seria a regra, não a exceção
Mesmo que eu perca navegadores antigos e ferramentas de API, pretendo manter o bloqueio de HTTP/1.1. Entendo se for código proprietário de um sistema financeiro legado, mas a Internet pública precisa se atualizar por conta própria
Como bloqueio o Google há muito tempo, toda requisição que diz vir do Google é falsa. Tento circular o blog por vários domínios aleatórios para quebrar relações e snapshots, e controlar por quais caminhos as pessoas descobrem meus textos
De quebra, recebi um teste de intrusão gratuito e concluí que minhas defesas e meu pipeline de processamento eram robustos. Por pressão de sobrevivência, 90% do tráfego de bots migrou para VPNs, e os endpoints de VPN estão brilhando como árvores de Natal
Eu poderia fornecer um feed de IPs de acesso descartável, mas os usuários teriam de ser devidamente verificados e ter o uso aprovado. Esse processo em si é divertido
Se não conseguir ler, dá para ver a versão arquivada em https://archive.ph/d3236
Não quero desativar o iCloud Private Relay só para ler algo quando nem sou um bot. Pelas outras respostas do autor, é uma boa implementação como site de teste, mas espero que outros administradores web não adotem todos esses métodos do mesmo jeito, se puderem evitar
Pelo corpo da resposta mostrar só 410 e a string
Sec-Fetch-Mode:, parece que fui classificado como bot. Não há nada para ler nem ver, então simplesmente vou embora; a Web moderna é horrívelO status de suporte pode ser conferido em https://caniuse.com/?search=sec-fetch-mode, e alguns headers em https://nochan.net/.env
PR_END_OF_FILE_ERROR, indicando que nem o handshake TLS foi concluídoImagino que mais de 99% do tráfego web seja de bots ou agentes, então estou pensando em remover a exibição de contagem de visitantes. O número não tem significado e faz o site parecer muito mais movimentado do que realmente é, mas hesito em reagir porque temo impedir pessoas reais de ler os textos ou baixar os livros
Se o bloqueio for necessário, em geral uma lista de permissão é mais eficaz que uma lista de bloqueio; se não der para aplicar uma lista de permissão, esse método também pode não ser uma boa solução
Ferramentas como Cloudflare e Anubis podem causar sérios problemas de acessibilidade, então prefiro limitação de frequência de requisições. É limpa e não prejudica a acessibilidade; para problemas temporários, bloqueios curtos de IP também funcionam bem
Pessoalmente, uso fail2ban para analisar logs HTTP e bloquear por N horas IPs que solicitam URLs proibidas em
robots.txt, caminhos comowp-login.php, ou que ultrapassam com frequência excessiva o limite de requisições. No momento estou testando o Anubis na UI web do GitSó com fail2ban já dá para bloquear bastante coisa, mas nos primeiros meses é preciso ajustar em detalhes ao ambiente
Primeiro eu detectava com o filtro
failregex = ^ - \S+ \[\] ".*?" 40[034]e depois adicionava a listas mais específicas; hoje uso cerca de 80 expressões regulares para bloquear todo o tráfego, e há muito tempo nenhuma requisição chega ao filtro genérico40[034]Mas, atrás de um load balancer ou proxy, é preciso algum método para obter o IP real, o que torna tanto o fail2ban quanto a abordagem do texto original mais trabalhosos
A julgar por estes comentários e pelas minhas tentativas de acesso, parece que não estão bloqueando só bots, mas todo o tráfego legítimo também
Aos domingos, dá para ver a maior variedade de navegadores e apps incomuns que as pessoas usam para navegar na Web; em dias úteis, há mais navegadores convencionais, o que vira um bom teste