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:
| Secret | Usado para |
|---|---|
JWT_SECRET | Tokens de usuários comuns. |
JWT_API_SECRET | Tokens 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:
# 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
| Evento | Pontos | Descrição |
|---|---|---|
| Honeypot hit | +100 | Acesso a rota falsa (armadilha para bots) |
| User-Agent malicioso | +50 | Scanner, bot malicioso detectado |
| Falha de login | +30 | Tentativa de login com credenciais inválidas |
| Rate limit excedido | +20 | Excedeu limite de requisições |
| Sem User-Agent | +15 | Requisição sem header User-Agent |
Thresholds e Ações
| Score | Ação | Descrição |
|---|---|---|
| 0-49 | Normal | Requisições processadas normalmente |
| 50-99 | Delay 2s | Adiciona delay de 2 segundos |
| 100-149 | Delay 5s | Adiciona delay de 5 segundos |
| 150+ | Bloqueio | Retorna 403 Forbidden |
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
| Evento | Descrição | Contexto |
|---|---|---|
auth.login.success | Login bem-sucedido | IP, user-agent, usuário |
auth.login.failed | Tentativa de login falhou | IP, user-agent, email tentado |
auth.logout | Logout | IP, usuário |
auth.token.refresh | Token renovado | IP, usuário |
auth.password.reset | Senha redefinida | IP, usuário |
user.created | Usuário criado | IP, admin que criou, dados do usuário |
user.updated | Usuário atualizado | IP, campos alterados |
user.deleted | Usuário deletado | IP, admin que deletou |
user.role.changed | Papel do usuário alterado | IP, papel anterior e novo |
module.toggled | Módulo ativado/desativado | IP, módulo, estado |
admin.action | Ação administrativa | IP, ação específica |
http.unauthorized | Resposta 401 | IP, URI, user-agent |
http.forbidden | Resposta 403 | IP, URI, user-agent |
http.rate_limited | Resposta 429 | IP, 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:
SECURITY_ALERT_WEBHOOK=https://hooks.slack.com/services/YOUR/WEBHOOK/URL
Payload enviado:
{
"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étodo | URI | Descrição |
|---|---|---|
| GET | /api/audit/logs | Lista logs de auditoria (paginado) |
| GET | /api/audit/stats | Estatísticas de eventos |
| DELETE | /api/audit/logs | Limpa 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.
// 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:
| Middleware | Aplicação | Função |
|---|---|---|
BotBlockerMiddleware | Global | Bloqueia scanners e ferramentas maliciosas |
HttpsEnforcerMiddleware | Produção | Bloqueia HTTP quando HTTPS é obrigatório |
SecurityHeadersMiddleware | Global | Adiciona headers de segurança (CSP, HSTS, etc.) |
Headers de Segurança
Headers adicionados automaticamente em todas as respostas:
X-Content-Type-Options: nosniffX-Frame-Options: DENYCross-Origin-Opener-Policy: same-originReferrer-Policy: strict-origin-when-cross-originContent-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.
| Vulnerabilidade | Proteção Implementada |
|---|---|
| A01: Broken Access Control | Middlewares de auth, OwnershipGuard, validação de papéis |
| A02: Cryptographic Failures | JWT com secrets fortes, HTTPS enforcer, cookies seguros |
| A03: Injection | Use prepared statements e allowlists para valores estruturais; o Kernel não corrige SQL concatenado dentro de módulos. |
| A04: Insecure Design | Arquitetura modular, princípio do menor privilégio |
| A05: Security Misconfiguration | Headers de segurança automáticos, configuração segura por padrão |
| A06: Vulnerable Components | Execute composer audit no deploy e mantenha PHP e dependências atualizados. |
| A07: Identity/Auth Failures | Rate limiting, ThreatScorer, auditoria de login |
| A08: Software/Data Integrity | Validação de input, sanitização, CSP |
| A09: Logging/Monitoring | AuditLogger, SecurityEventLogger, alertas automáticos |
| A10: Server-Side Request Forgery | Qualquer 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=falseem produção. - Configure
APP_ENV=productionpara 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
OwnershipGuardpara verificar posse de recursos. - Gere secrets JWT com
openssl rand -hex 32(mínimo 32 chars). - Configure
COOKIE_SECURE=trueeCOOKIE_SAMESITE=Laxem produção. - Use HTTPS em produção — configure
TRUST_PROXY=truecom proxy reverso. - Configure
SECURITY_ALERT_WEBHOOKpara 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ção | Aplicação prática |
|---|---|
| Autenticação | Defina explicitamente se a rota é pública, de usuário, admin ou machine-to-machine. |
| Autorização e IDOR | Consulte o recurso pelo identificador junto com o UUID do dono; não confie apenas no UUID recebido pela URL. |
| Entrada | Valide presença, tipo, tamanho, formato e domínio permitido. Rejeite campos desconhecidos quando isso fizer sentido. |
| SQL | Use parâmetros para valores e allowlist para nomes de coluna, direção de ordenação e outros identificadores. |
| Abuso | Defina rate limit mais restritivo para login, recuperação, envio de e-mail e operações custosas. |
| Segredos | Nunca retorne tokens, hashes, credenciais, DSN ou mensagens internas de exceção. |
| Efeitos repetidos | Use idempotência em pagamentos, webhooks e comandos que não podem ser duplicados. |
| Auditoria | Registre ações relevantes sem armazenar senha, token completo ou dado pessoal desnecessário. |
| Testes | Cubra 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
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]);
}
}
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.