Looking to hire Laravel developers? Try LaraJobs

antibot-laravel maintained by marcelocardozo

Description
Sistema de detecção e bloqueio de bots, proxies e VPNs para Laravel
Last update
2026/05/13 00:18 (dev-main)
License
Links
Downloads
1

Comments
comments powered by Disqus

Antibot para Laravel

Sistema de detecção e bloqueio de bots, proxies e VPNs para Laravel.

Detecta automaticamente ferramentas de automação (Selenium, Puppeteer, Playwright, Cypress, PhantomJS, etc.), analisa fingerprints do navegador, verifica proxies/VPNs via ProxyCheck.io e bloqueia visitantes suspeitos com base em um sistema de pontuação configurável.

Requisitos

  • PHP 8.2+
  • Laravel 11, 12 ou 13
  • Chave de API do ProxyCheck.io (gratuito)

Instalação

composer require marcelocardozo/antibot-laravel

Publicar configuração, migrations e assets:

php artisan vendor:publish --provider="MarceloCardozo\Antibot\AntibotServiceProvider"

Ou publicar separadamente:

# Apenas configuração
php artisan vendor:publish --tag=antibot-config

# Apenas migrations
php artisan vendor:publish --tag=antibot-migrations

# Apenas assets (JS)
php artisan vendor:publish --tag=antibot-assets

# Apenas views (templates)
php artisan vendor:publish --tag=antibot-views

Executar as migrations:

php artisan migrate

Configuração

Adicione ao .env:

ANTIBOT_PROXYCHECK_API_KEY=sua-chave-aqui
ANTIBOT_TEST_IP=192.145.220.95
Variável Descrição
ANTIBOT_PROXYCHECK_API_KEY Chave de API do ProxyCheck.io
ANTIBOT_TEST_IP IP usado em localhost para testes (substitui 127.0.0.1)

O arquivo config/antibot.php contém todas as opções:

return [
    'route_prefix'       => 'antibot',       // Prefixo das rotas
    'route_middleware'    => ['web'],          // Middleware das rotas
    'pagina_inicial'     => '/',              // Página com detecção completa
    'redirect_url'       => '',               // Redirecionar após aprovação (vazio = não redireciona)
    'block_redirect_url' => '/',              // Redirecionar bloqueados (padrão: página inicial)
    'tempo_minimo'       => 5000,             // Tempo mínimo de verificação (ms)
    'tela_carregamento'  => 'spinner',        // Template: 'spinner' ou 'cloudflare'
    'score_minimo'       => 50,               // Score mínimo para bloquear
    'bloquear_bot'       => true,             // Bloquear bots detectados
    'bloquear_proxy'     => true,             // Bloquear proxies
    'bloquear_vpn'       => true,             // Bloquear VPNs
    'paises_permitidos'  => ['BR'],           // Países permitidos (vazio = todos)
    'regras'             => [ ... ],          // 40+ regras de detecção com pontuação
];

Uso

1. Página inicial (detecção completa)

Na Blade da página onde o visitante entra no site, adicione a diretiva @antibot:

<!DOCTYPE html>
<html>
<head></head>
<body>
    @antibot

    <h1>Meu site</h1>
</body>
</html>

Quando o visitante acessa a página:

  1. A página é ocultada e um loading é exibido
  2. 40+ verificações client-side são executadas
  3. APIs server-side analisam IP, proxy, VPN e User-Agent
  4. O resultado é salvo no banco de dados
  5. Se aprovado: a página é liberada
  6. Se bloqueado: redireciona para block_redirect_url ou exibe 404

2. Páginas secundárias (verificação rápida)

Para páginas internas que só precisam verificar se o visitante já foi aprovado:

<body>
    @antibotVerify

    <h1>Página interna</h1>
</body>

3. Middleware (proteção server-side)

Para proteger rotas no server-side (bloqueia bots que pulam o JavaScript):

// routes/web.php
Route::middleware('antibot.verify')->group(function () {
    Route::get('/area-protegida', [MeuController::class, 'index']);
    Route::get('/checkout', [CheckoutController::class, 'index']);
});

O middleware verifica no banco se o IP do visitante já foi aprovado. Se não existir registro ou se estiver bloqueado, redireciona para block_redirect_url ou retorna 404.

4. Combinando proteções

Para proteção máxima, combine middleware + diretiva Blade:

// routes/web.php
Route::middleware('antibot.verify')->group(function () {
    Route::get('/oferta', [OfertaController::class, 'index']);
});
{{-- resources/views/oferta/index.blade.php --}}
<body>
    @antibot
    <h1>Oferta exclusiva</h1>
</body>

Redirecionamento de bloqueados

Por padrão, visitantes bloqueados ou não verificados são redirecionados para / (página inicial). Para customizar:

// config/antibot.php

// Padrão: redireciona para a página inicial
'block_redirect_url' => '/',

// Path relativo (mesma aplicação)
'block_redirect_url' => '/acesso-negado',

// URL externa
'block_redirect_url' => 'https://google.com',

// Vazio = exibe o template 404 do pacote
'block_redirect_url' => '',

Funciona tanto no middleware (server-side) quanto no JavaScript (client-side).

Facade

O pacote disponibiliza uma Facade para uso programático:

use MarceloCardozo\Antibot\Facades\Antibot;

// Resolver IP real do visitante
$ip = Antibot::resolveIp($request);

// Verificar proxy/VPN
$data = Antibot::check($ip);
// Retorna: ['ip', 'asn', 'provider', 'isocode', 'city', 'proxy', 'vpn', ...]

// Detectar dispositivo
$device = Antibot::detect($request->userAgent());
// Retorna: ['bot', 'client_name', 'device_type', 'os_name', ...]

// Flags de servidor suspeitas
$flags = Antibot::getServerFlags($request);
// Retorna: ['tool_ua', 'short_ua', 'no_accept_language', ...]

Models

O pacote registra dois models Eloquent que permitem consultar os dados de detecção no seu código:

  • MarceloCardozo\Antibot\Models\Acesso — Registro de cada visitante analisado
  • MarceloCardozo\Antibot\Models\Navegacao — Páginas visitadas por cada acesso

Campos disponíveis

Acesso:

Campo Tipo Descrição
id bigint ID auto-incremento
data_hora timestamp Data/hora do acesso
ip string IP do visitante
url text URL acessada
asn string ASN do provedor
hostname string Hostname do IP
provider string Provedor de internet
organisation string Organização
isocode string Código do país (BR, US, etc.)
regioncode string Código da região
city string Cidade
proxy string "yes" ou "no"
vpn string "yes" ou "no"
bot string "yes" ou "no"
client_name string Navegador (Chrome, Firefox, etc.)
client_type string Tipo do client (browser, app, etc.)
client_version string Versão do navegador
device_brand string Marca do dispositivo
device_model string Modelo do dispositivo
device_type string Tipo (desktop, smartphone, tablet)
os_name string Sistema operacional
os_platform string Plataforma
os_version string Versão do SO
os_family string Família do SO
bloqueado string "true" ou "false"
motivo_bloqueio text Motivo(s) do bloqueio
created_at timestamp Criado em
updated_at timestamp Atualizado em

Navegacao:

Campo Tipo Descrição
id bigint ID auto-incremento
data_hora timestamp Data/hora da navegação
ip string IP do visitante
url text URL visitada
referrer text Página de origem
acesso_id bigint FK para antibot_acessos
created_at timestamp Criado em
updated_at timestamp Atualizado em

Exemplo em Controller

<?php

namespace App\Http\Controllers;

use MarceloCardozo\Antibot\Models\Acesso;
use MarceloCardozo\Antibot\Models\Navegacao;

class AntibotController extends Controller
{
    // Listar todos os acessos com paginação
    public function index()
    {
        $acessos = Acesso::latest()->paginate(20);

        return view('antibot.index', compact('acessos'));
    }

    // Detalhes de um acesso específico + suas navegações
    public function show(Acesso $acesso)
    {
        $acesso->load('navegacoes');

        return view('antibot.show', compact('acesso'));
    }

    // Listar apenas bloqueados
    public function bloqueados()
    {
        $bloqueados = Acesso::where('bloqueado', 'true')
            ->latest()
            ->paginate(20);

        return view('antibot.bloqueados', compact('bloqueados'));
    }

    // Estatísticas
    public function stats()
    {
        $total = Acesso::count();
        $bloqueados = Acesso::where('bloqueado', 'true')->count();
        $aprovados = Acesso::where('bloqueado', 'false')->count();
        $proxies = Acesso::where('proxy', 'yes')->count();
        $vpns = Acesso::where('vpn', 'yes')->count();
        $bots = Acesso::where('bot', 'yes')->count();

        $hoje = Acesso::whereDate('created_at', today())->count();
        $bloqueadosHoje = Acesso::where('bloqueado', 'true')
            ->whereDate('created_at', today())
            ->count();

        return view('antibot.stats', compact(
            'total', 'bloqueados', 'aprovados',
            'proxies', 'vpns', 'bots',
            'hoje', 'bloqueadosHoje'
        ));
    }
}

Consultas úteis

use MarceloCardozo\Antibot\Models\Acesso;
use MarceloCardozo\Antibot\Models\Navegacao;

// Últimos 10 acessos bloqueados
$bloqueados = Acesso::where('bloqueado', 'true')
    ->latest()
    ->take(10)
    ->get();

// Acessos de um IP específico
$acessos = Acesso::where('ip', '177.0.0.1')->get();

// Verificar se um IP está bloqueado
$estaBloqueado = Acesso::where('ip', '177.0.0.1')
    ->latest()
    ->first()
    ?->isBloqueado(); // true ou false

// Navegação de um acesso (páginas visitadas)
$acesso = Acesso::find(1);
$paginas = $acesso->navegacoes;

// Acessos por país
$porPais = Acesso::select('isocode')
    ->selectRaw('count(*) as total')
    ->groupBy('isocode')
    ->orderByDesc('total')
    ->get();

// Acessos com proxy ou VPN
$suspeitos = Acesso::where('proxy', 'yes')
    ->orWhere('vpn', 'yes')
    ->latest()
    ->get();

// Total de bloqueados hoje
$total = Acesso::where('bloqueado', 'true')
    ->whereDate('created_at', today())
    ->count();

// Acessos de um navegador específico
$chrome = Acesso::where('client_name', 'Chrome')->get();

// Acessos mobile bloqueados
$mobileBloqueados = Acesso::where('device_type', 'smartphone')
    ->where('bloqueado', 'true')
    ->get();

Relacionamentos

// Acesso -> Navegacoes (HasMany)
$acesso = Acesso::find(1);
$navegacoes = $acesso->navegacoes; // Collection de Navegacao

// Navegacao -> Acesso (BelongsTo)
$navegacao = Navegacao::find(1);
$acesso = $navegacao->acesso; // Model Acesso

// Eager loading
$acessos = Acesso::with('navegacoes')->latest()->get();

Regras de detecção

O sistema usa 40+ regras com pontuação individual. Quando a soma dos pontos atinge o score_minimo (padrão: 50), o visitante é bloqueado.

Automação direta (80 pts cada)

Regra Detecta
webdriver navigator.webdriver === true
chromedriver Variáveis $cdc_ injetadas pelo ChromeDriver
selenium Propriedades globais do Selenium
puppeteer __puppeteer_evaluation_script__
playwright __playwright, __pw_manual
cypress window.Cypress, window.cy
phantomjs callPhantom, _phantom
nightmare __nightmare
webdriverio wdio, __wdio
testcafe %testCafeDriverInstance%
browserless __browserless, __chrome_aws_lambda
stack_automacao Stack trace com nomes de ferramentas

Fingerprint e ambiente

Regra Pts Detecta
ua_suspeito 60 Keywords de bot no User-Agent
webdriver_patched 60 Undetected-chromedriver (getter customizado)
chrome_falso 30 UA diz Chrome mas window.chrome ausente
webgl_software 30 Renderer software (SwiftShader, Mesa)
tela_zero 30 Dimensões da tela = 0
canvas_vazio 25 Canvas renderiza imagem vazia
mobile_sem_touch 25 UA mobile sem suporte touch
sem_color_depth 20 Color depth inválido
platform_mismatch 20 UA e navigator.platform divergem
perm_inconsistente 20 Permissões inconsistentes
audio_vazio 20 Audio fingerprint vazio

Para a lista completa, consulte config/antibot.php.

Desativar uma regra

// config/antibot.php
'regras' => [
    'historico_curto' => ['ativo' => false, 'pts' => 5],  // desativada
    'webdriver'       => ['ativo' => true,  'pts' => 80],  // ativa
],

Templates de loading

Dois templates disponíveis, configuráveis em config/antibot.php:

  • spinner — Spinner minimalista (padrão)
  • cloudflare — Visual estilo Cloudflare security check
'tela_carregamento' => 'cloudflare',

Para personalizar, publique as views e edite em resources/views/vendor/antibot/templates/.

Rotas registradas

Método URI Descrição
GET /antibot/config Configuração pública (JSON)
GET /antibot/api/proxycheck Detecção de proxy/VPN
GET /antibot/api/device-detector Detecção de dispositivo
POST /antibot/api/salvar Salvar registro de acesso
GET /antibot/api/sessao Verificar status do visitante
POST /antibot/api/navegacao Registrar navegação
GET /antibot/templates/{template} Templates (404, spinner, cloudflare)

O prefixo /antibot é configurável via config('antibot.route_prefix').

Licença

MIT