PHPackages                             codedart/laravel-slide-captcha - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Security](/categories/security)
4. /
5. codedart/laravel-slide-captcha

ActiveLibrary[Security](/categories/security)

codedart/laravel-slide-captcha
==============================

Self-hosted slide CAPTCHA package for Laravel.

v0.2.0(1mo ago)04MITPHPPHP &gt;=7.4

Since Jun 1Pushed 1mo agoCompare

[ Source](https://github.com/codedartdev/laravel-slide-captcha)[ Packagist](https://packagist.org/packages/codedart/laravel-slide-captcha)[ RSS](/packages/codedart-laravel-slide-captcha/feed)WikiDiscussions main Synced 1w ago

READMEChangelogDependencies (18)Versions (3)Used By (0)

Laravel Slide CAPTCHA
=====================

[](#laravel-slide-captcha)

CAPTCHA visual self-hosted para Laravel, baseado no desafio de arrastar uma peça até a posição correta da imagem.

O pacote gera um desafio, recorta uma peça da imagem, salva temporariamente os arquivos gerados em um disco privado, normalmente S3, e retorna URLs internas temporariamente assinadas para o navegador. A posição correta fica somente no backend e é armazenada em cache por poucos segundos.

Introdução
----------

[](#introdução)

O `codedart/laravel-slide-captcha` ajuda a proteger formulários Laravel contra envios automatizados.

Use esta biblioteca quando você precisa de um CAPTCHA simples, visual e controlado pela própria aplicação, sem depender de serviços externos como Google reCAPTCHA, hCaptcha ou Cloudflare Turnstile.

Ela resolve um problema comum em formulários públicos:

- Bots enviando formulários de contato.
- Cadastros automatizados.
- Tentativas repetidas em páginas sensíveis.
- Necessidade de validar interação humana sem enviar dados para provedores externos.

O usuário vê uma imagem, arrasta a peça até o ponto correto, gira a peça quando o desafio exigir rotação e, se acertar, recebe um token temporário. Esse token deve ser enviado junto com o formulário final.

Requisitos
----------

[](#requisitos)

- PHP `>= 7.4`
- Laravel `>= 8`
- Composer
- Extensão PHP `gd`
- Cache configurado no Laravel
- Disco de storage privado legível pela aplicação
- Recomendado: Redis para cache
- Recomendado: S3 ou storage compatível com S3 para armazenar as imagens geradas

Dependências usadas pelo pacote:

- `illuminate/support`
- `illuminate/routing`
- `illuminate/cache`
- `illuminate/filesystem`
- `illuminate/http`
- `illuminate/validation`
- `intervention/image`

Para usar S3 em um projeto Laravel, garanta que o driver esteja instalado e configurado. Em muitos projetos Laravel modernos, isso é feito com:

```
composer require league/flysystem-aws-s3-v3
```

Depois configure o disco `s3` no `.env` da aplicação Laravel.

Instalação
----------

[](#instalação)

Instale o pacote com Composer:

```
composer require codedart/laravel-slide-captcha
```

O Laravel deve registrar o service provider automaticamente.

Este pacote não exige migrations, não exige publicação de assets e não exige publicação de views para funcionar.

Os assets JavaScript e CSS são servidos por rotas internas do próprio pacote.

Em produção, o pacote serve automaticamente os assets minificados de `resources/dist`. Os fontes legíveis ficam em `resources/assets`.

As rotas criadas pelo pacote são:

```
GET  /slide-captcha/assets/slide-captcha.css
GET  /slide-captcha/assets/slide-captcha.js
GET  /slide-captcha/new
GET  /slide-captcha/generated/{path}
POST /slide-captcha/verify

```

Para conferir se as rotas foram registradas:

```
php artisan route:list
```

Se você estiver testando este pacote localmente, antes de publicar no Packagist, adicione um repositório path no `composer.json` da aplicação Laravel:

```
{
  "repositories": [
    {
      "type": "path",
      "url": "../laravel-slide-captcha",
      "options": {
        "symlink": true
      }
    }
  ]
}
```

Depois instale:

```
composer require codedart/laravel-slide-captcha:@dev
```

### Build dos assets

[](#build-dos-assets)

O pacote já inclui os arquivos minificados prontos para uso.

Se você alterar `resources/assets/slide-captcha.js` ou `resources/assets/slide-captcha.css`, gere a build novamente:

```
composer build-assets
```

Esse comando atualiza:

```
resources/dist/slide-captcha.min.js
resources/dist/slide-captcha.min.css

```

O objetivo é reduzir o tamanho dos arquivos enviados ao navegador e diminuir o custo de parse no dispositivo do usuário.

### Testes

[](#testes)

Para rodar a suíte de testes do pacote:

```
composer install
composer test
```

Os testes cobrem a máscara puzzle, a rotação, a análise de movimento e a validação angular.

Configuração
------------

[](#configuração)

A configuração principal é feita pelo `.env` da aplicação Laravel.

Exemplo realista:

```
SLIDE_CAPTCHA_ENABLED=true
SLIDE_CAPTCHA_CACHE_STORE=redis
SLIDE_CAPTCHA_TTL=120

SLIDE_CAPTCHA_IMAGE_WIDTH=320
SLIDE_CAPTCHA_IMAGE_HEIGHT=180
SLIDE_CAPTCHA_PIECE_MIN_SIZE=42
SLIDE_CAPTCHA_PIECE_MAX_SIZE=58
SLIDE_CAPTCHA_TOLERANCE=8
SLIDE_CAPTCHA_ROTATION_ENABLED=true
SLIDE_CAPTCHA_ROTATION_STEP_DEGREES=15
SLIDE_CAPTCHA_ROTATION_MAX_DEGREES=90
SLIDE_CAPTCHA_ROTATION_TOLERANCE_DEGREES=8

SLIDE_CAPTCHA_ROUTE_PREFIX=slide-captcha
SLIDE_CAPTCHA_MIDDLEWARE=web

SLIDE_CAPTCHA_STORAGE_DISK=s3
SLIDE_CAPTCHA_GENERATED_PATH=slide-captcha/generated
SLIDE_CAPTCHA_TEMPORARY_URL_TTL=300

SLIDE_CAPTCHA_VALIDATE_MOVEMENT=true
SLIDE_CAPTCHA_MOVEMENT_MIN_POINTS=8
SLIDE_CAPTCHA_MOVEMENT_MIN_DURATION_MS=250
SLIDE_CAPTCHA_MOVEMENT_MAX_DURATION_MS=15000
SLIDE_CAPTCHA_MOVEMENT_MAX_SAME_Y_RATIO=0.9

SLIDE_CAPTCHA_DDOS_ENABLED=true
SLIDE_CAPTCHA_DDOS_MODE=adaptive
SLIDE_CAPTCHA_DDOS_REPORTING_SINKS=cache
SLIDE_CAPTCHA_DDOS_BROADCAST_ENABLED=auto
```

### Variáveis disponíveis

[](#variáveis-disponíveis)

`SLIDE_CAPTCHA_ENABLED`

Ativa ou desativa o CAPTCHA. Use `false` apenas em ambientes controlados, como testes locais.

`SLIDE_CAPTCHA_CACHE_STORE`

Define o cache usado para armazenar desafios e tokens. Exemplo: `redis`. Se ficar vazio, usa o cache padrão do Laravel.

`SLIDE_CAPTCHA_TTL`

Tempo de validade do desafio, em segundos. Padrão: `120`.

`SLIDE_CAPTCHA_IMAGE_WIDTH`

Largura da imagem do CAPTCHA. Padrão: `320`.

`SLIDE_CAPTCHA_IMAGE_HEIGHT`

Altura da imagem do CAPTCHA. Padrão: `180`.

`SLIDE_CAPTCHA_PIECE_MIN_SIZE`

Tamanho mínimo da peça recortada. Padrão: `42`.

`SLIDE_CAPTCHA_PIECE_MAX_SIZE`

Tamanho máximo da peça recortada. Padrão: `58`.

`SLIDE_CAPTCHA_TOLERANCE`

Margem de erro permitida, em pixels. Padrão: `8`.

`SLIDE_CAPTCHA_ROTATION_ENABLED`

Ativa a rotação obrigatória da peça. Padrão: `true`.

Quando ativa, o encaixe no background aparece girado, a peça começa em `0°` e o usuário precisa girá-la antes de verificar.

`SLIDE_CAPTCHA_ROTATION_STEP_DEGREES`

Quantidade de graus aplicada a cada clique nos botões de rotação. Padrão: `15`.

`SLIDE_CAPTCHA_ROTATION_MAX_DEGREES`

Maior ângulo aleatório usado pelo desafio. Padrão: `90`.

`SLIDE_CAPTCHA_ROTATION_TOLERANCE_DEGREES`

Margem de erro permitida para a rotação. Padrão: `8`.

`SLIDE_CAPTCHA_ROUTE_PREFIX`

Prefixo das rotas internas do pacote. Padrão: `slide-captcha`.

`SLIDE_CAPTCHA_MIDDLEWARE`

Middlewares aplicados às rotas do CAPTCHA. Padrão: `web`.

`SLIDE_CAPTCHA_STORAGE_DISK`

Disco onde as imagens geradas serão salvas. Padrão: `s3`.

`SLIDE_CAPTCHA_GENERATED_PATH`

Pasta dentro do disco configurado onde as imagens temporárias serão salvas. Padrão: `slide-captcha/generated`.

`SLIDE_CAPTCHA_TEMPORARY_URL_TTL`

Tempo de validade das URLs internas assinadas das imagens, em segundos. Padrão: `300`.

`SLIDE_CAPTCHA_BACKGROUNDS_PATH`

Diretório local usado para substituir as imagens base padrão do pacote.

Se esta variável não for definida, o pacote usa as imagens incluídas em:

```
vendor/codedart/laravel-slide-captcha/resources/backgrounds

```

Você pode usar um caminho absoluto:

```
SLIDE_CAPTCHA_BACKGROUNDS_PATH=/var/www/my-app/storage/app/captcha-backgrounds
```

Ou um caminho relativo à raiz do projeto Laravel:

```
SLIDE_CAPTCHA_BACKGROUNDS_PATH=storage/app/captcha-backgrounds
```

O diretório deve conter imagens `.jpg`, `.jpeg`, `.png` ou `.webp`.

`SLIDE_CAPTCHA_VALIDATE_MOVEMENT`

Ativa a análise básica do movimento do mouse ou toque. Padrão: `true`.

`SLIDE_CAPTCHA_MOVEMENT_MIN_POINTS`

Quantidade mínima de pontos de movimento enviados pelo navegador.

`SLIDE_CAPTCHA_MOVEMENT_MIN_DURATION_MS`

Duração mínima do movimento, em milissegundos.

`SLIDE_CAPTCHA_MOVEMENT_MAX_DURATION_MS`

Duração máxima do movimento, em milissegundos.

`SLIDE_CAPTCHA_MOVEMENT_MAX_SAME_Y_RATIO`

Proporção máxima permitida de movimentos com o mesmo eixo Y. Ajuda a rejeitar movimentos muito lineares.

### Proteção DDoS e relatórios de ataque

[](#proteção-ddos-e-relatórios-de-ataque)

O pacote inclui uma camada adaptativa para proteger os endpoints internos do CAPTCHA.

Ela atua antes da geração de imagem em:

```
GET /slide-captcha/new

```

E registra sinais suspeitos em:

```
POST /slide-captcha/verify

```

A identidade padrão combina:

- IP do request.
- Hash do user-agent.
- Hash da sessão Laravel, quando existir.

Quando uma identidade excede os limites, o pacote responde com `429`:

```
{
  "success": false,
  "reason": "ddos_protection",
  "retry_after": 300
}
```

O header `Retry-After` também é enviado.

Configuração mínima recomendada:

```
SLIDE_CAPTCHA_DDOS_ENABLED=true
SLIDE_CAPTCHA_DDOS_MODE=adaptive
SLIDE_CAPTCHA_DDOS_NEW_MAX_ATTEMPTS=60
SLIDE_CAPTCHA_DDOS_NEW_DECAY_SECONDS=60
SLIDE_CAPTCHA_DDOS_NEW_BLOCK_SECONDS=300
SLIDE_CAPTCHA_DDOS_VERIFY_MAX_ATTEMPTS=120
SLIDE_CAPTCHA_DDOS_VERIFY_DECAY_SECONDS=60
SLIDE_CAPTCHA_DDOS_VERIFY_BLOCK_SECONDS=300
SLIDE_CAPTCHA_DDOS_FAILURE_MAX_ATTEMPTS=20
SLIDE_CAPTCHA_DDOS_FAILURE_DECAY_SECONDS=60
SLIDE_CAPTCHA_DDOS_FAILURE_BLOCK_SECONDS=600
SLIDE_CAPTCHA_DDOS_SCORE_THRESHOLD=80
SLIDE_CAPTCHA_DDOS_SCORE_DECAY_SECONDS=120
SLIDE_CAPTCHA_DDOS_SCORE_BLOCK_SECONDS=600
```

Use `SLIDE_CAPTCHA_DDOS_MODE=monitor` se quiser apenas observar e emitir relatórios, sem bloquear tráfego.

#### Persistência dos relatórios

[](#persistência-dos-relatórios)

Os relatórios são gravados por sinks configuráveis.

O padrão é cache temporário:

```
SLIDE_CAPTCHA_DDOS_REPORTING_SINKS=cache
SLIDE_CAPTCHA_DDOS_CACHE_TTL=3600
SLIDE_CAPTCHA_DDOS_CACHE_LIMIT=500
```

Você também pode ativar múltiplos sinks:

```
SLIDE_CAPTCHA_DDOS_REPORTING_SINKS=cache,s3_batch
```

Sinks disponíveis:

- `none`: não persiste; apenas emite eventos em tempo real para listeners/broadcast.
- `cache`: mantém uma janela temporária em cache/Redis.
- `database`: grava linha a linha em uma tabela.
- `s3_batch`: acumula em cache e descarrega em arquivo `.jsonl` no disco configurado.

Para usar banco, publique a migration:

```
php artisan vendor:publish --tag=slide-captcha-migrations
php artisan migrate
```

Depois configure:

```
SLIDE_CAPTCHA_DDOS_REPORTING_SINKS=database
SLIDE_CAPTCHA_DDOS_DATABASE_TABLE=slide_captcha_attack_reports
```

Para usar batch em S3 ou storage compatível:

```
SLIDE_CAPTCHA_DDOS_REPORTING_SINKS=cache,s3_batch
SLIDE_CAPTCHA_DDOS_S3_BATCH_DISK=s3
SLIDE_CAPTCHA_DDOS_S3_BATCH_PATH=slide-captcha/attack-reports/{date}/{datetime}-{uuid}.jsonl
SLIDE_CAPTCHA_DDOS_S3_BATCH_CACHE_TTL=3600
```

Agende o flush no scheduler da aplicação:

```
use Illuminate\Support\Facades\Schedule;

Schedule::command('slide-captcha:flush-attack-reports')->everyMinute();
```

Cada arquivo S3 usa JSON Lines: um relatório JSON por linha.

#### Reverb e eventos em tempo real

[](#reverb-e-eventos-em-tempo-real)

O pacote dispara o evento:

```
CodeDart\SlideCaptcha\Events\SlideCaptchaAttackDetected
```

Quando `SLIDE_CAPTCHA_DDOS_BROADCAST_ENABLED=auto`, o evento só é transmitido se `broadcasting.default` estiver configurado como `reverb`.

Configuração:

```
SLIDE_CAPTCHA_DDOS_BROADCAST_ENABLED=auto
SLIDE_CAPTCHA_DDOS_BROADCAST_CHANNEL=private-slide-captcha.attacks
SLIDE_CAPTCHA_DDOS_BROADCAST_EVENT=slide-captcha.attack
```

Payload do relatório:

```
{
  "id": "9f7a2f4f4c3d4c6d91dbff9b82b02c1e",
  "occurred_at": "2026-06-01T12:00:00-03:00",
  "occurred_at_timestamp": 1780329600,
  "action": "blocked",
  "severity": "critical",
  "endpoint": "new",
  "reason": "rate_limit_new",
  "ip": "203.0.113.10",
  "identity_hash": "sha256...",
  "user_agent_hash": "sha256...",
  "session_hash": "sha256...",
  "retry_after": 300,
  "score": 84,
  "limit_key": "slide_captcha_ddos:rate:new:...",
  "request_method": "GET",
  "request_path": "slide-captcha/new",
  "details": {
    "attempts": 61,
    "max_attempts": 60
  }
}
```

Motivos comuns de ataque ou suspeita:

- `rate_limit_new`
- `rate_limit_verify`
- `failure_limit`
- `score_threshold`
- `validation_failed`
- `not_found`
- `used`
- `expired`
- `invalid_position`
- `invalid_rotation`
- `movement_too_short`
- `movement_too_fast`
- `movement_too_slow`
- `movement_too_linear`

#### Métricas para dashboard próprio

[](#métricas-para-dashboard-próprio)

Este pacote não renderiza dashboard. Para consultar métricas e montar sua própria tela, injete `SlideCaptchaMetrics`.

Exemplo mínimo:

```
