
Automatize o bloqueio de bots maliciosos que tentam acessar seu servidor
Uma TUI, uma interface web e uma CLI que ajudam você a configurar seu servidor para bloquear bots maliciosos sem se esconder atrás de um CDN.
Funciona em conjunto com o NGINX e seu firewall existente (iptables ou nftables), em dois planos separados:
O aplicativo faz o possível para não bloquear seu acesso ao servidor, mas você o usa por sua conta e risco. E observe que ele é licenciado sob AGPL, então se você o estiver usando comercialmente, certifique-se de obedecer à letra da licença.
Do crates.io:``` cargo install stop-bots
Ou compile a partir de um checkout:```
cargo install --path .
Um binário Linux x86_64 pré-compilado está disponível nas releases do GitHub.
Requer Rust 1.88 ou mais recente para compilar. Apenas Linux na prática: ele invoca
systemctl, nginx -t e nft/iptables, então embora compile em outros lugares, não será
muito útil lá.
Execute o binário sem argumentos para iniciar a TUI, stop-bots web para as mesmas telas em
um navegador (veja A interface web), ou veja stop-bots --help para a lista completa de
subcomandos da CLI. A TUI e a CLI podem ser usadas juntas. Configure tudo na TUI e
depois use a CLI em um crontab para manter as regras atualizadas.
Você pode sair do aplicativo, ou voltar de um popup/submenu, com 'q' ou Escape.
Você pode alternar entre o tema escuro e claro com 't'. O aplicativo tentará detectar automaticamente o tema, mas para algumas combinações de terminal e multiplexador não há informação suficiente disponível para fazer a escolha correta.
1–4 (ou d/b/s/p) saltam diretamente para uma tela; Esquerda/Direita, ou seus aliases
vim h/l, percorrem-nas; ? alterna uma referência completa de atalhos a qualquer momento, e :
abre uma paleta de comandos listando cada ação por nome. Tab / Shift+Tab sempre se movem entre
os painéis da tela atual, nunca entre telas.
O Dashboard possui tudo que acaba no script de firewall; as configurações de Site possuem tudo que acaba na configuração do NGINX. Essa divisão decide onde cada configuração vive.
Up/Down fluem entre as três listas; m alterna o modo geo. Pressione F para renderizar as
regras de firewall atuais em um script — o
popup também tem um interruptor "aplicar após escrever" (Space) para realmente aplicá-lo
imediatamente, em vez de aplicá-lo manualmente depois. Mais três teclas agem sobre todo o
host: u baixa todas as listas, a aplica ambos os planos (NGINX, depois o firewall), e
w coloca este console atrás do NGINX — os mesmos três que o navegador tem como botões e um
painel.Tab para focá-lo) contendo as escolhas
para todo o host que moldam a configuração gerada — o que uma requisição bloqueada recebe de volta (veja abaixo),
se deve servir um robots.txt gerado, e limitação de taxa — acima de cada site NGINX
descoberto em disco, cada um com um status ao vivo "atualizado / desatualizado / não encontrado" e ações para
aplicar a política atual a um site ou a todos eles. Alterar qualquer uma dessas configurações muda
cada site aplicado para STALE, que é o seu sinal para reaplicar. Abrir um site permite
substituir sua política de categoria/bot, ativar qualquer uma das seis regras de forma de requisição, e listar
caminhos isentos de bloqueio.NOT BLOCKED/BLOCKED (mostrado em vermelho). Tab/Shift+Tab alternam a qual dos dois painéis
Up/Down se aplicam; f alterna um filtro compartilhado (todos / apenas não bloqueados / apenas bloqueados);
Enter bloqueia a linha NOT BLOCKED selecionada, ou desbloqueia se já estiver BLOCKED.
i inspeciona o endereço selecionado: quais dos feeds de reputação o listam, se ele está
dentro de um intervalo de crawler publicado (que é o que separa um Googlebot real de um user
agent que apenas diz ser), a qual país pertence, e como quais contas ele tentou
fazer login. Tudo isso a partir de listas que este host já baixou — não há consulta de DNS reverso
ou whois aqui, porque um registro PTR é escrito por quem detém o endereço
e seria texto fornecido pelo atacante que se lê como autoritativo.Configurações de bots, onde cada fonte de lista e cada bot individual vive:
Configurações de site, onde as escolhas do NGINX para todo o host ficam acima de cada site encontrado em disco:
Proteção Dinâmica, a visão ao vivo do que está atingindo o servidor agora:
Bots conhecidos, por categoria (scanner / mecanismo de busca / crawler de IA), obtidos de
ArcJet's Well-Known Bots,
ai.robots.txt e a
lista NGINX Ultimate Bad Bot Blocker.
Bloquear uma categoria injeta uma regra if ($http_user_agent ...) na configuração NGINX
de cada site (apply-blocks / a/A das configurações de Site).
Muitas requisições, via limitação de taxa do próprio NGINX. Diferente de tudo mais aqui, isso é aplicado pelo NGINX no momento da requisição em vez de analisar um log depois. Desligado por padrão: um limite ajustado para o site errado afasta visitantes reais.
Educadamente, primeiro — um robots.txt gerado opcional listando cada bot que você está bloqueando,
para os crawlers que o respeitam, mais o caminho honeypot abaixo. Desligado por padrão, porque
substitui o que seu site serve em /robots.txt hoje.
Exceto onde você disser o contrário — isenções de caminho por site, para que você possa bloquear crawlers de IA
em todos os lugares exceto /blog.
Requisições que não parecem um navegador, por site. Seis regras independentes, cada uma com seu próprio interruptor e cada uma desligada por padrão — um interruptor por regra para que, se algo seu parar de funcionar, você possa identificar qual regra causou:
Duas salvaguardas se aplicam a todas elas, e são aplicadas em vez de deixadas para você:
server HTTPS. Navegadores
não fazem HTTP/2 sem TLS, então em um bloco listen 80 simples toda requisição é HTTP/1.1 —
incluindo o redirecionamento que um navegador faz a caminho do HTTPS. Seus blocos de porta 80 e porta 443
geralmente compartilham um server_name, então a configuração alcança ambos; apenas o de TLS recebe
essas regras. As regras de forma de cabeçalho funcionam sobre HTTP simples e são escritas em ambos./.well-known/ é sempre isento assim que qualquer regra está ativada. É onde o Let's Encrypt
busca seu desafio HTTP-01, sobre HTTP/1.1 sem Accept e frequentemente sem User-Agent —
sem a isenção seu certificado para de renovar semanas depois.Uma escolha para todo o host, nas configurações de Site. Estes não são códigos de status intercambiáveis — cada um diz algo diferente, e a diferença importa mais para os clientes que você não pretendia capturar:
| Opção | Para que serve |
|---|---|
403 Forbidden (padrão) | diz que o bloqueio foi deliberado; o único sobre o qual um humano capturado por engano pode agir |
404 Not Found | esconde que algo foi bloqueado |
410 Gone | pede a crawlers bem-comportados que descartem a URL para sempre — prefira isto ao 403 quando você está afastando crawlers em vez de atacantes |
429 Too Many Requests | diz a um cliente educado para recuar e tentar novamente |
418 I'm a teapot | a piada da RFC 2324. Funciona; só não é registrado pela IANA, e o NGINX o envia com corpo vazio |
444 close connection | nenhuma resposta; mais barato, mas indistinguível do servidor estar fora do ar |
Tarpit | responde 403 mas goteja o corpo a um byte por segundo, então o cliente espera em vez de seguir em frente |
O tarpit é a opção mais gentil para um falso positivo — um cliente capturado por engano é desacelerado,
não recusado — e a mais severa em custo para um bot, cuja conexão fica ociosa. Duas coisas a
saber antes de escolhê-lo: ele mantém uma das suas conexões de worker durante todo o tempo também, então
uma enxurrada de clientes em tarpit compete com visitantes reais por worker_connections; e quanto
tempo ele realmente dura depende de como o NGINX escolhe escrever um corpo de erro pequeno, o que é
anotado no TODO.md como precisando de verificação contra um servidor real.
Cada um destes é um interruptor independente no painel "Bloqueio automático" do Dashboard, e cada um adiciona um bloqueio de firewall temporário que expira por conta própria e é readicionado se o comportamento continuar.
Eles rodam em um temporizador interno que relê seus logs de acesso SSH e NGINX a cada minuto — mas apenas enquanto a TUI ou a interface web estiver rodando. Qualquer uma delas mantém o mesmo agendamento, no mesmo banco de dados, então deixar a interface web ativa é suficiente; nada é detectado quando nenhuma está rodando. Para um servidor sem nenhum processo stop-bots nele, veja Desassistido, via cron abaixo.
/.env, /.git/config,
/wp-config.php e similares é conclusiva por si só, então isso não precisa de limiar. A
lista embutida deliberadamente deixa de fora caminhos que são legítimos em algum lugar — /wp-login.php,
/wp-admin/, /xmlrpc.php, /phpmyadmin — já que bloquear seu próprio administrador seria
pior do que perder um scanner que o detector de 404 captura de qualquer forma. Adicione os seus com
set-probe-paths.Disallow: no robots.txt gerado e linkado
em lugar nenhum. Alcançá-lo significa ignorar o robots.txt, o que nada legítimo faz por acidente —
o sinal mais forte aqui, e o bloqueio mais longo. Precisa da geração de robots.txt ativada para
funcionar.Mais três olham como um cliente se comporta em vez do que ele pede. Todos os três estão desligados por padrão, porque cada um tem um falso positivo que não pode descartar sozinho — e todos os três isentam crawlers de mecanismos de busca verificados, que de outra forma corresponderiam a todos eles:
304 conta como um recurso buscado).
Não pode ajudar em um site que não serve nenhum recurso — uma API JSON pura.Referer. Enfraquecido por
Referrer-Policy: no-referrer e ferramentas de privacidade; o limiar de caminhos distintos é o que
o torna utilizável./24 IPv4 são sinalizados
na mesma passagem, bloqueie o /24. Desligado por padrão — bloquear 256 endereços porque três
se comportaram mal é dano colateral por design. (IPv6 é diferente e não precisa de interruptor: uma detecção
sempre bloqueia o /64, porque um /64 é uma LAN, a mesma coisa que um único endereço IPv4
representa. Bloquear o único endereço que um atacante IPv6 usou não pararia nada
— eles têm 2^64 a mais.)Tudo acima é gerado. Se algo disso está em vigor é uma questão
separada, e stop-bots status é o que responde a ela:```
stop-bots status
Sete verificações, e a primeira é a que vale a pena ter: as regras geradas
estão realmente no kernel, ou apenas no disco? Um host real ficou em execução por três semanas com
48.860 regras de drop em `/etc/stop-bots/firewall.nft` e um conjunto de regras vazio,
porque escrever o script e carregá-lo são dois passos e nada tinha alguma vez
olhado para o segundo.
O resto: o conjunto de regras sobreviverá a um reboot (`nftables.service` ativado?), o
script ainda corresponde às regras, os blocos NGINX estão aplicados, o serviço de consola
está a executar o binário que nomeia, há espaço para a base de dados, e os
detetores conseguem ler os seus logs.
Sai com código diferente de zero se algo for **CRITICAL**, por isso funciona como uma verificação de
monitorização. `--quiet` imprime apenas o que precisa de atenção, que é a forma para cron:```
0 * * * * /usr/local/bin/stop-bots status --quiet
Uma verificação que não pôde ser executada — nft list precisa de root — reporta UNKNOWN, nunca
OK. Uma verificação de integridade que diz que está tudo bem porque não conseguiu olhar é
pior do que nenhuma, porque é acreditada.
O mesmo relatório está no Dashboard tanto no console quanto na TUI, obtido
a cada hora pelo cron interno em vez de a cada renderização: nft list num grande
conjunto de regras são megabytes de texto.
Toda decisão de firewall acima é gerada, nunca aplicada automaticamente: render-firewall
(ou a tecla f do Dashboard) escreve um script iptables ou nftables para você revisar e aplicar
você mesmo, e recusa-se a escrever um que bloquearia uma sessão SSH atualmente conectada.
Três coisas podem aplicá-lo para você, e todas as três precisam que você peça: o popup de renderização da TUI
("aplicar após escrever") ou sua tecla a, o painel de firewall do console web ("executar após
escrever") ou seu botão "Aplicar tudo", e batch --apply a partir de um crontab que você escreveu — veja
Desassistido, a partir do cron. Nenhum deles é um efeito colateral de nada
automático: o cron interno renderiza o script e nunca o executa.
O mesmo se aplica ao lado do NGINX: alterar uma configuração só altera o que seria escrito.
As configurações do site mostram cada site como STALE até você aplicar.
Desligar um detector nunca remove os bloqueios que ele já adicionou — esses expiram por conta própria.
"Parar de detectar" e "desfazer o que foi detectado" são deliberadamente separados; o segundo é a
tela de Proteção Dinâmica ou remove-firewall-rule.
Há também uma contagem simples de logs de acesso, independente do bloqueio: record-access-stats /
list-access-stats contam com que frequência cada user agent aparece em requisições bem-sucedidas (não-erro),
para que você possa ver quem está realmente visitando além de quem está sendo bloqueado.
stop-bots batch é uma passagem por tudo o que a TUI faz manualmente: atualizar cada lista,
escanear os logs, escrever as regras de bloqueio do NGINX e o script de firewall.```
0 4 * * * root /usr/local/bin/stop-bots batch --apply --ssh-log /var/log/auth.log
*/10 * * * * root /usr/local/bin/stop-bots batch --apply --no-fetch --ssh-log /var/log/auth.log
Ele não diz nada quando tudo funcionou, então uma execução noturna saudável não te envia email. Um passo falhado imprime para stderr e define um estado de saída não-zero, que é o que faz o cron avisar-te sobre isso. Executa-o uma vez manualmente com `--verbose` primeiro — isso imprime uma linha por passo, e é a forma mais fácil de ver o que ele está realmente a fazer.
**`--apply` é o que faz com que ele imponha algo.** Sem ele, o `batch` escreve a configuração do NGINX e o script da firewall e para: a configuração não faz nada até um reload, um script não faz nada até ser executado. Esse é o padrão deste projeto em todo o lado, e continua a ser o padrão aqui.
O `batch` e um front-end de longa duração coexistem em segurança. A TUI, a UI web e o `batch` registam todos o que fizeram através das mesmas chaves na mesma base de dados, por isso quem chegar primeiro a uma tarefa fá-la e os outros descobrem que já não está devida — não obténs duas passagens de deteção, e o painel "Scheduled tasks" do Dashboard mostra o que realmente aconteceu em vez de afirmar que está tudo em atraso. Se já deixas a UI web a correr, a entrada noturna do `batch` é um cinto e suspensórios em vez de um requisito; se não deixas, é a única coisa que mantém a deteção atualizada.
**Com `--apply`, a proteção contra bloqueio de SSH pode recusar — e recusar significa que nada é aplicado.** Ela recusa se as regras bloquearem um cliente que está ligado neste momento, *e* se nenhum log de SSH puder ser lido de todo, porque então a verificação não pôde ser executada. O `render-firewall` interativo apenas imprime uma nota nesse segundo caso, partindo do princípio de que há um humano a vigiar o terminal; a partir do cron não há ninguém. **Passa `--ssh-log` explicitamente**: o cron corre como root, por isso `/var/log/auth.log` normalmente lê-se bem, mas num host apenas com journald o `journalctl` sob cron pode voltar vazio, que é exatamente o caso em que ele recusa. O `--force` sobrepõe-se à proteção se for mesmo isso que queres.
Um passo a falhar nunca para os outros, e as metades do NGINX e da firewall são independentes — um reload do NGINX falhado ainda deixa a firewall aplicada, e vice-versa.
O `batch` regista cada passo contra o mesmo agendamento que o cron interno da TUI usa, por isso os dois concordam sobre o que já foi executado em vez de ambos o fazerem, e o painel "Scheduled tasks" do Dashboard mostra o que o teu cron real fez.
# A UI web
O `stop-bots web` serve os mesmos cinco ecrãs num navegador.```
stop-bots web
Ele vincula 127.0.0.1:8787 — acessível apenas a partir dessa máquina — e imprime uma palavra-passe gerada uma vez, na primeira execução. Acede-lhe a partir do teu portátil através de um túnel SSH:``` ssh -L 8787:127.0.0.1:8787 your-server
então abra <http://127.0.0.1:8787/>.

O console segue a configuração de tema claro ou escuro do sistema operacional, com um botão de alternância no
cabeçalho; as capturas de tela da TUI acima são do tema escuro, estas do claro. As teclas que a
TUI usa também funcionam aqui: `1`–`4` alternam entre telas, `/` foca a caixa de pesquisa, `?` abre a Ajuda.

Três ações de host inteiro ficam no cabeçalho, no navegador como botões e na TUI
como teclas individuais:
- **Atualizar tudo** (`u`) baixa todas as listas de bots, todos os intervalos de IP de crawlers, todos os
feeds de reputação *habilitados* e todos os países *selecionados* — o mesmo conjunto que `stop-bots batch`
busca, do mesmo plano. A falha de uma fonte não impede as restantes, e nada é
aplicado até que algo o faça.
- **Aplicar tudo** (`a`) escreve e recarrega a configuração do NGINX, depois escreve e executa o
script de firewall. Os dois planos são independentes: seja qual for que falhe, o outro ainda tem
a sua vez, porque um host meio aplicado é melhor do que um onde um erro de sintaxe do NGINX também deixou
o firewall desatualizado.
- **Acesso Web** (`w`) configura o NGINX para servir o próprio console — consulte
[Por trás do NGINX](#behind-nginx-a-subdomain-or-a-path-prefix).
## Como serviço (Debian)```
sudo stop-bots install web
Grava /etc/systemd/system/stop-bots-web.service, cria /var/lib/stop-bots (0700 — contém
o hash da palavra-passe da consola) e /etc/stop-bots, gera uma palavra-passe se não existir
nenhuma, e ativa e inicia a unit.
--dry-run imprime todo o plano e não altera nada. Este é o único comando do
projeto que inicia um daemon, por isso comece por aí. --prefix <dir> escreve a mesma árvore
num local que pode ler sem root. Se a unit já existir e a tiver editado, o
instalador para e avisa, em vez de substituir a sua edição; --force se era isso que pretendia.
O serviço corre como root, porque a consola reescreve /etc/nginx, escreve o script
da firewall, e executa nginx -t e systemctl reload nginx. Não há uma separação sem
privilégios que mantenha o conjunto de funcionalidades intacto. A unit inclui o hardening que
sobrevive a esse requisito e um comentário a indicar qual hardening foi omitido e porquê.
O endereço de bind, a allowlist de hosts e o prefixo de caminho estão deliberadamente fora da
unit — o servidor em execução volta a lê-los da base de dados, por isso colocá-los em
ExecStart dar-lhes-ia duas fontes de verdade. Altere-os com stop-bots web --save ... e reinicie.
Uma coisa muda quando isto corre como root: a tarefa diária RenderFirewall do cron
interno pode agora escrever /etc/stop-bots/firewall.nft, o que não conseguia quando executava a consola
manualmente como o seu próprio utilizador. Nada aplica esse script — executá-lo continua a ser
responsabilidade sua.
Apenas Debian é verificado, porque é o que foi testado; a unit é muito provavelmente correta em qualquer distribuição systemd, mas o caminho dos logs SSH que assume é o do Debian.
Fazer bind a algo que não seja loopback exige uma segunda flag deliberada, porque esta consola pode reescrever a firewall e a configuração do NGINX do host onde corre:``` stop-bots web --bind 0.0.0.0:8787 --expose --allowed-hosts admin.example.com --save
`--allowed-hosts` não é opcional na prática: uma requisição que carrega um nome de host que não está
listado é recusada. É isso que faz o DNS rebinding contra o console falhar, e é
por isso que um servidor exposto acessado por nome precisa que o nome seja especificado.
Coloque-o atrás do NGINX com TLS — o mesmo NGINX que esta ferramenta está protegendo. Se o fizer, e o
proxy definir `X-Forwarded-For`, avise o console de que ele pode confiar nesse cabeçalho, ou ele não conseguirá
determinar de qual endereço uma requisição realmente veio:```
stop-bots web --bind 127.0.0.1:8787 # and set web:trust_forwarded_for
Por trás do TLS, defina também web:secure_cookie. Sem isso, um navegador enviará o cookie de sessão também para um URL http:// do mesmo host.
web:trust_forwarded_for importa mais do que parece. Sem ele, cada requisição atrás de um proxy chega de 127.0.0.1, então o console não consegue distinguir um cliente de outro — o que significa que uma enxurrada de tentativas de login compartilha o mesmo balde de throttle que você, e a proteção que impede você de bloquear seu próprio endereço não tem com o que comparar. Com ele, ambos funcionam por cliente.
O console pode configurar isso para você, e o TUI também (w no Dashboard). Ambos escrevem a configuração do NGINX, registram o prefixo de caminho e adicionam o nome do host à allowlist — as três coisas que precisam concordar, porque um prefixo ausente faz cada link sair do bloco location e um nome de host ausente faz cada requisição virar um 403. Ambos validam com nginx -t antes que a configuração possa entrar em vigor, revertem se isso falhar, e registram o novo endereço apenas depois que ele foi validado.
Dois modos, e path é o padrão por um motivo: ele adiciona um bloco location a um site que você já tem, então o console herda o certificado desse site. Um subdomínio precisa do seu próprio, e até que certbot --nginx -d <host> tenha sido executado, o formulário de senha e o cookie de sessão deste console atravessam a rede em texto claro.
O restante desta seção é a mesma coisa feita à mão, o que vale a pena ler uma vez mesmo que você use o painel — a armadilha da barra final abaixo é o erro que ele existe para prevenir.
Um subdomínio é a implantação mais simples, e a que você deve escolher se puder:```nginx server { server_name stopbots.example.com; location / { proxy_pass http://127.0.0.1:8787; proxy_set_header Host $host; } }
| `-s` | `--server` | `SERVER` | `http://localhost:8080` | URL do servidor |
| `-t` | `--token` | `TOKEN` | - | Token de autenticação |
| `-o` | `--output` | `FILE` | stdout | Arquivo de saída |
| `-f` | `--format` | `FORMAT` | `json` | Formato de saída (json, yaml, table) |
| `-v` | `--verbose` | - | `false` | Ativar saída detalhada |
| `-q` | `--quiet` | - | `false` | Suprimir saída não essencial |
| `--timeout` | - | `SECONDS` | `30` | Tempo limite da requisição em segundos |
| `--retry` | - | `COUNT` | `3` | Número de tentativas em caso de falha |
| `--insecure` | - | - | `false` | Ignorar verificação de certificado TLS |
### Exemplos
```bash
# Listar todos os alvos
scanner targets list
# Obter detalhes de um alvo específico
scanner targets get --id abc123
# Criar um novo alvo
scanner targets create --name "web-server" --host 192.168.1.100
# Excluir um alvo
scanner targets delete --id abc123
# Exportar resultados em formato JSON
scanner scan --target abc123 --output results.json --format json
# Executar com saída detalhada
scanner scan --target abc123 --verbose
# Usar um arquivo de configuração personalizado
scanner --config /path/to/config.yaml scan --target abc123
O scanner oferece suporte a um arquivo de configuração YAML para definir opções padrão:
server: http://localhost:8080
token: your-api-token-here
output: results.json
format: json
timeout: 60
retry: 5
insecure: false
targets:
- name: web-server
host: 192.168.1.100
ports:
- 80
- 443
- 8080
- name: db-server
host: 192.168.1.200
ports:
- 3306
- 5432
As seguintes variáveis de ambiente podem ser usadas para substituir as configurações padrão:
| Variável | Descrição | Padrão |
|---|---|---|
SCANNER_SERVER | URL do servidor | http://localhost:8080 |
SCANNER_TOKEN | Token de autenticação | - |
SCANNER_OUTPUT | Arquivo de saída | stdout |
SCANNER_FORMAT | Formato de saída | json |
SCANNER_TIMEOUT | Tempo limite da requisição | 30 |
SCANNER_RETRY | Número de tentativas | 3 |
SCANNER_INSECURE | Ignorar verificação TLS | false |
| Código | Descrição |
|---|---|
0 | Sucesso |
1 | Erro geral |
2 | Uso incorreto do comando |
3 | Erro de autenticação |
4 | Recurso não encontrado |
5 | Tempo limite da requisição excedido |
Erro: Conexão recusada
Verifique se o servidor está em execução e se a URL está correta:
curl -v http://localhost:8080/health
Erro: Não autorizado
Verifique se o token de autenticação está correto e não expirou:
scanner auth verify --token your-api-token-here
Erro: Tempo limite da requisição excedido
Aumente o valor do tempo limite usando a flag --timeout:
scanner scan --target abc123 --timeout 120
Erro: Certificado TLS inválido
Use a flag --insecure para ignorar a verificação do certificado (apenas para ambientes de teste):
scanner scan --target abc123 --insecure
Para remover o scanner do seu sistema:
# Se instalado via pip
pip uninstall scanner-cli
# Se instalado via npm
npm uninstall -g scanner-cli
# Se instalado a partir do código-fonte
cd scanner-cli
make uninstall
Este projeto está licenciado sob a Licença MIT - consulte o arquivo LICENSE para obter detalhes.
Contribuições são bem-vindas! Consulte CONTRIBUTING.md para obter diretrizes.
Se você encontrar algum problema ou tiver dúvidas, abra uma issue no GitHub.
Esta ferramenta destina-se apenas a testes de segurança autorizados e fins educacionais. Os autores não se responsabilizam por qualquer uso indevido ou danos causados por esta ferramenta. Sempre obtenha permissão por escrito antes de testar qualquer sistema que você não possua.``` stop-bots web --allowed-hosts stopbots.example.com --save
**Um prefixo de caminho também funciona**, mas o console precisa ser informado sobre ele — ele precisa
gerar cada link, ação de formulário, redirecionamento e caminho de cookie com o prefixo já
incluído, e não consegue adivinhar:```
stop-bots web --base-path /stop-bots --allowed-hosts example.com --save
| -s | --server | SERVER | http://localhost:8080 | URL do servidor |
| -t | --token | TOKEN | null | Token de autenticação |
| -c | --config | CONFIG | null | Caminho do arquivo de configuração |
| -v | --verbose | VERBOSE | false | Saída detalhada |
| -q | --quiet | QUIET | false | Modo silencioso |
| -d | --debug | DEBUG | false | Modo de depuração |
| -h | --help | HELP | false | Exibir ajuda |
| -V | --version | VERSION | false | Exibir versão |
# Iniciar o servidor
python3 server.py
# Executar o cliente
python3 client.py
# Executar com opções
python3 client.py -s http://localhost:8080 -t mytoken -v
project/
├── server.py # Arquivo principal do servidor
├── client.py # Arquivo principal do cliente
├── config.py # Arquivo de configuração
├── requirements.txt # Dependências do projeto
├── README.md # Documentação do projeto
└── tests/ # Diretório de testes
├── test_server.py
└── test_client.py
# Clonar o repositório
git clone https://github.com/example/project.git
cd project
# Criar ambiente virtual
python3 -m venv venv
source venv/bin/activate
# Instalar dependências
pip install -r requirements.txt
# Executar todos os testes
pytest
# Executar com cobertura
pytest --cov=. --cov-report=html
# Executar testes específicos
pytest tests/test_server.py -v
# Formatar código
black .
# Verificar lint
flake8 .
# Verificar tipos
mypy .
# Construir imagem
docker build -t project:latest .
# Executar contêiner
docker run -d -p 8080:8080 project:latest
# Iniciar serviços
docker-compose up -d
# Parar serviços
docker-compose down
Porta já em uso
# Encontrar processo usando a porta
lsof -i :8080
# Encerrar processo
kill -9 <PID>
Permissão negada
# Tornar executável
chmod +x server.py
Módulo não encontrado
# Instalar dependências
pip install -r requirements.txt
# Visualizar logs
tail -f /var/log/project/server.log
# Filtrar logs
grep "ERROR" /var/log/project/server.log
git checkout -b feature/AmazingFeature)git commit -m 'Add some AmazingFeature')git push origin feature/AmazingFeature)Este projeto está licenciado sob a Licença MIT - consulte o arquivo LICENSE para obter detalhes.
```nginx
location /stop-bots/ {
proxy_pass http://127.0.0.1:8787; # NO trailing slash
proxy_set_header Host $host;
}
**A barra final em `proxy_pass` importa, e sua ausência é todo o truque.**
Sem ela, o NGINX passa o caminho completo adiante e o `stop-bots` vê
`/stop-bots/whatever`, que é o que ele agora serve e gera. *Com* uma barra
final, o NGINX remove o prefixo — e então o navegador resolve os links na página
em relação à raiz do domínio, cai fora do bloco `location`, e tudo retorna 404. Nenhum
cuidado do lado do servidor pode corrigir isso, então o prefixo precisa sobreviver ao
proxy.
Nada impõe isso de fora, mas a falha é ruidosa em vez de sutil: com o
prefixo configurado, uma requisição sem prefixo é um 404 simples em vez de uma página que
funciona pela metade.
## O que ele não fará
Duas coisas estão faltando de propósito, e a tela de Ajuda diz isso com os motivos:
- **Ele não desbloqueará algo que uma lista baixada bloqueou** — a próxima atualização dessa
lista desfaria isso silenciosamente.
- **Ele não mudará sua própria senha.** Use `stop-bots web --set-password` no host.
Ele também se recusa a bloquear o endereço do qual você está conectado, o que tiraria o
console que você usaria para desfazer isso.
**Costumava ser três.** Aplicar o script de firewall era a terceira, com o argumento de que
executá-lo é a única operação que pode tirar o host da rede. Isso agora está
disponível — "Apply everything" no Dashboard (`a` na TUI), ou a caixa "run it after
writing" no painel de firewall — porque a proteção que o torna seguro a partir do cron o torna seguro a partir de um
botão: as regras são verificadas contra os clientes atualmente logados via SSH, na
ordem em que o próprio script as avaliará, e uma regra que bloquearia um deles é uma
recusa em vez de um aviso. Inicie o console com `--no-apply` para recuperar o comportamento antigo
de apenas escrita.
As tentativas de login são limitadas. Não porque a senha seja adivinhável — ela é gerada,
144 bits — mas porque verificá-la executa Argon2id, e deixar um chamador não autenticado
conduzir isso o mais rápido que conseguir postar é uma negação de serviço contra o host que esta ferramenta
deveria estar protegendo. Dez tentativas erradas são gratuitas; além disso, um cliente recua
exponencialmente, e um limite global limita a CPU independentemente de quantos endereços as
tentativas vêm.
## Executando o NGINX em um contêiner
Se o NGINX está no Docker e sua configuração está em um bind mount, `systemctl reload nginx` não recarrega
nada. Aponte os dois comandos para o contêiner — isso se aplica à CLI e à
TUI também:```
stop-bots set-nginx-commands \
--test "docker exec web nginx -t" \
--reload "docker exec web nginx -s reload"
O comando é dividido em palavras e executado diretamente. Ele nunca passa por um shell, portanto ;,
| e $VAR são caracteres comuns em vez de sintaxe.
Como o código está organizado, como é testado e as regras segundo as quais é escrito estão em CONTRIBUTING.md. O processo de release está em RELEASING.md.
Você pode entrar em contato comigo em [email protected].
Copyright (C) 2026 Marko Ivankovic
Este programa é software livre: você pode redistribuí-lo e/ou modificá-lo sob os termos da GNU Affero General Public License, conforme publicada pela Free Software Foundation, seja a versão 3 da Licença, ou (a seu critério) qualquer versão posterior.
Consulte o arquivo LICENSE para o texto completo da Licença.
Licenciamento alternativo NÃO está disponível.
| Regra | Afasta, além de bots |
|---|
| HTTP/1.0 e HTTP/1.1 | crawlers e clientes de API que não falam HTTP/2 |
Sem cabeçalho Accept | alguns clientes de API não enviam nenhum |
Sem Accept-Language | ferramentas de privacidade o removem |
User-Agent vazio/ausente | scripts e verificações de integridade frequentemente o omitem |
Host é um IP puro | quebra o acesso ao site por IP |
| TLS 1.0 / 1.1 | apenas clientes muito antigos |