Referência v3
Voltar à plataforma

Segurança

Controles implementados, responsabilidades dos módulos e verificações necessárias antes de publicar uma rota.

Autenticação JWT

O sistema usa dois secrets JWT distintos com suporte a key rotation:

SecretUsado para
JWT_SECRETTokens de usuários comuns.
JWT_API_SECRETTokens de admin_system e tokens de API.

Todo token é validado com: assinatura, expiração, iss, aud, jti (blacklist) e UUID do usuário.

Key Rotation

O sistema suporta rotação de secrets sem downtime usando múltiplas versões:

env
# Configuração para key rotation
JWT_SECRET_KID=v2              # Chave ativa para novos tokens
JWT_SECRET_v1=secret_antigo    # Ainda válido para tokens existentes
JWT_SECRET_v2=secret_novo      # Usado para novos tokens

Tokens assinados com v1 continuam válidos enquanto novos tokens usam v2. Remova a chave anterior somente depois da maior validade possível dos tokens emitidos e da confirmação nos logs de que ela não é mais usada.

ThreatScorer — Sistema de Pontuação de Ameaças

O ThreatScorer detecta comportamento suspeito acumulando pontos por IP. Quando o score atinge um threshold, o sistema aplica delays progressivos ou bloqueia o acesso.

Pontuação de Eventos

EventoPontosDescrição
Honeypot hit+100Acesso a rota falsa (armadilha para bots)
User-Agent malicioso+50Scanner, bot malicioso detectado
Falha de login+30Tentativa de login com credenciais inválidas
Rate limit excedido+20Excedeu limite de requisições
Sem User-Agent+15Requisição sem header User-Agent

Thresholds e Ações

ScoreAçãoDescrição
0-49NormalRequisições processadas normalmente
50-99Delay 2sAdiciona delay de 2 segundos
100-149Delay 5sAdiciona delay de 5 segundos
150+BloqueioRetorna 403 Forbidden
TTL Automático

O score expira automaticamente após 1 hora. Após esse período, o IP volta ao score 0. Isso permite que IPs legítimos se recuperem de falsos positivos.

Storage

O ThreatScorer usa Redis quando disponível (distribuído entre múltiplos servidores) ou file storage (servidor único). A configuração é automática baseada na presença de REDIS_HOST no .env.

Sistema de Auditoria

O sistema registra automaticamente eventos de segurança na tabela audit_logs e emite logs estruturados para stderr (compatível com Fail2Ban, Datadog, CloudWatch).

Eventos Registrados

EventoDescriçãoContexto
auth.login.successLogin bem-sucedidoIP, user-agent, usuário
auth.login.failedTentativa de login falhouIP, user-agent, email tentado
auth.logoutLogoutIP, usuário
auth.token.refreshToken renovadoIP, usuário
auth.password.resetSenha redefinidaIP, usuário
user.createdUsuário criadoIP, admin que criou, dados do usuário
user.updatedUsuário atualizadoIP, campos alterados
user.deletedUsuário deletadoIP, admin que deletou
user.role.changedPapel do usuário alteradoIP, papel anterior e novo
module.toggledMódulo ativado/desativadoIP, módulo, estado
admin.actionAção administrativaIP, ação específica
http.unauthorizedResposta 401IP, URI, user-agent
http.forbiddenResposta 403IP, URI, user-agent
http.rate_limitedResposta 429IP, URI, limite excedido

Detecção de Comportamento Suspeito

O sistema detecta automaticamente padrões suspeitos e emite alertas:

  • Força bruta: 10+ falhas de login em 5 minutos do mesmo IP
  • Scanning: Múltiplos 404 em rotas diferentes
  • Honeypot hits: Acesso a rotas falsas
  • Anomalias de user-agent: Padrões de bots maliciosos

Webhook de Alertas

Configure SECURITY_ALERT_WEBHOOK no .env para receber alertas em tempo real:

env
SECURITY_ALERT_WEBHOOK=https://hooks.slack.com/services/YOUR/WEBHOOK/URL

Payload enviado:

json
{
  "alert": "BRUTE_FORCE_DETECTED",
  "dados": {
    "ip": "192.168.1.100",
    "falhas_5min": 12,
    "threshold": 10,
    "acao_sugerida": "Bloquear IP temporariamente"
  },
  "timestamp": "2026-04-19T14:30:00+00:00"
}

Endpoints de Auditoria (Admin)

MétodoURIDescrição
GET/api/audit/logsLista logs de auditoria (paginado)
GET/api/audit/statsEstatísticas de eventos
DELETE/api/audit/logsLimpa logs antigos

Rate Limiting

Dupla camada: por IP e por usuário autenticado. Usa Redis (distribuído) ou File (servidor único). Configurável por rota com middleware RateLimitMiddleware.

php
// 5 requisições por minuto por IP
$rateLimit = [RateLimitMiddleware::class, ['limit' => 5, 'window' => 60]];
$router->post('/api/register', [Controller::class, 'register'], [$rateLimit]);

Middlewares de Segurança

Middlewares aplicados automaticamente pelo Kernel:

MiddlewareAplicaçãoFunção
BotBlockerMiddlewareGlobalBloqueia scanners e ferramentas maliciosas
HttpsEnforcerMiddlewareProduçãoBloqueia HTTP quando HTTPS é obrigatório
SecurityHeadersMiddlewareGlobalAdiciona headers de segurança (CSP, HSTS, etc.)

Headers de Segurança

Headers adicionados automaticamente em todas as respostas:

  • X-Content-Type-Options: nosniff
  • X-Frame-Options: DENY
  • Cross-Origin-Opener-Policy: same-origin
  • Referrer-Policy: strict-origin-when-cross-origin
  • Content-Security-Policy (configurável)
  • Strict-Transport-Security (HTTPS apenas)

Cobertura relacionada ao OWASP Top 10

Os itens abaixo são controles de apoio, não uma certificação automática. A cobertura final depende do código de cada módulo, das permissões do banco, do proxy, das dependências e da operação do servidor.

VulnerabilidadeProteção Implementada
A01: Broken Access ControlMiddlewares de auth, OwnershipGuard, validação de papéis
A02: Cryptographic FailuresJWT com secrets fortes, HTTPS enforcer, cookies seguros
A03: InjectionUse prepared statements e allowlists para valores estruturais; o Kernel não corrige SQL concatenado dentro de módulos.
A04: Insecure DesignArquitetura modular, princípio do menor privilégio
A05: Security MisconfigurationHeaders de segurança automáticos, configuração segura por padrão
A06: Vulnerable ComponentsExecute composer audit no deploy e mantenha PHP e dependências atualizados.
A07: Identity/Auth FailuresRate limiting, ThreatScorer, auditoria de login
A08: Software/Data IntegrityValidação de input, sanitização, CSP
A09: Logging/MonitoringAuditLogger, SecurityEventLogger, alertas automáticos
A10: Server-Side Request ForgeryQualquer módulo que faça requisições externas deve validar esquema, host, DNS resolvido, redirecionamentos e bloquear redes privadas.

Boas Práticas

  • Sempre use APP_DEBUG=false em produção.
  • Configure APP_ENV=production para ativar validações extras.
  • Nunca concatene variáveis em SQL — use prepared statements.
  • Nunca acesse tabelas de outros módulos diretamente.
  • Valide todos os inputs no Controller ou Service.
  • Use OwnershipGuard para verificar posse de recursos.
  • Gere secrets JWT com openssl rand -hex 32 (mínimo 32 chars).
  • Configure COOKIE_SECURE=true e COOKIE_SAMESITE=Lax em produção.
  • Use HTTPS em produção — configure TRUST_PROXY=true com proxy reverso.
  • Configure SECURITY_ALERT_WEBHOOK para monitoramento em tempo real.
  • Monitore logs de auditoria regularmente via /api/audit/logs.
  • Implemente rate limiting em todas as rotas públicas.

Checklist antes de ativar uma rota

VerificaçãoAplicação prática
AutenticaçãoDefina explicitamente se a rota é pública, de usuário, admin ou machine-to-machine.
Autorização e IDORConsulte o recurso pelo identificador junto com o UUID do dono; não confie apenas no UUID recebido pela URL.
EntradaValide presença, tipo, tamanho, formato e domínio permitido. Rejeite campos desconhecidos quando isso fizer sentido.
SQLUse parâmetros para valores e allowlist para nomes de coluna, direção de ordenação e outros identificadores.
AbusoDefina rate limit mais restritivo para login, recuperação, envio de e-mail e operações custosas.
SegredosNunca retorne tokens, hashes, credenciais, DSN ou mensagens internas de exceção.
Efeitos repetidosUse idempotência em pagamentos, webhooks e comandos que não podem ser duplicados.
AuditoriaRegistre ações relevantes sem armazenar senha, token completo ou dado pessoal desnecessário.
TestesCubra sucesso, validação, ausência de login, papel incorreto, acesso a recurso alheio, repetição e rate limit.

Exemplo mínimo de rota autenticada

O UUID do usuário vem da identidade validada. O repository deve incluir esse UUID na consulta, impedindo que um usuário altere um recurso de outro apenas trocando o parâmetro da URL.

php
<?php

use Ramsey\Uuid\Uuid;
use Src\Kernel\Auth;

// 20 alterações por minuto, autenticação obrigatória e circuit breaker do banco.
$router->patch(
    '/api/tarefas/{uuid}',
    [TarefaController::class, 'atualizar'],
    Auth::user(limit: 20, key: 'tarefas.atualizar', db: true),
);

final class TarefaController
{
    public function __construct(private readonly TarefaService $service) {}

    public function atualizar(Request $request): Response
    {
        $usuarioUuid = (string) Auth::id($request);
        $tarefaUuid = (string) $request->param('uuid');
        $titulo = trim((string) ($request->body['titulo'] ?? ''));

        if (!Uuid::isValid($tarefaUuid)) {
            return Response::json(['error' => 'Identificador inválido.'], 422);
        }
        if ($titulo === '' || mb_strlen($titulo) > 160) {
            return Response::json(['error' => 'Título deve ter entre 1 e 160 caracteres.'], 422);
        }

        // O service/repository busca por tarefaUuid + usuarioUuid.
        $tarefa = $this->service->atualizarDoUsuario($tarefaUuid, $usuarioUuid, $titulo);

        return Response::json(['data' => $tarefa]);
    }
}
Formato não concede acesso

Uuid::isValid() valida somente o formato. A autorização acontece quando a consulta exige simultaneamente o UUID do recurso e o UUID do usuário autenticado.