PHP MVC Boilerplate v1.1.2
Primeira release de segurança do PHP MVC Boilerplate.
Esta versão implementa proteções ativas contra os ataques mais comuns em aplicações web PHP, corrige vulnerabilidades identificadas na versão v1.1.1 e completa funcionalidades que estavam pendentes, sem introduzir quebras de compatibilidade.
✅ Atualização fortemente recomendada para todos os projetos em produção.
🔒 Segurança — Correções Críticas
Rate Limiting (novo — proteção contra força bruta)
A ausência de limitação de tentativas era a vulnerabilidade mais grave da versão anterior. Um atacante podia realizar ataques de força bruta ou credential stuffing indefinidamente sem qualquer bloqueio.
- Implementado
RateLimitMiddlewarecom armazenamento em arquivo (sem dependência de Redis ou Memcached). - Três perfis pré-configurados:
login— 5 tentativas por 15 minutos, chave por IP + e-mail (bloqueia o par, não o IP isolado).forgot— 3 tentativas por 60 minutos por IP.api— 60 requisições por minuto por IP.
- Respostas automáticas com header
Retry-Aftere código HTTP 429. - Suporte a respostas JSON para clientes de API e redirecionamento com flash message para formulários HTML.
- Limpeza automática de arquivos expirados (executada probabilisticamente em 1% das requisições, sem custo fixo).
Security Headers (novo)
- Implementado
SecurityHeadersMiddlewarecomContent-Security-Policy,Permissions-PolicyeStrict-Transport-Security(HSTS ativado automaticamente em produção com HTTPS). - Header
X-Powered-Byremovido em todas as respostas para não expor stack tecnológico.
Debug em produção (corrigido)
A página errors/debug.php expunha stack trace completo, versão do PHP, caminhos internos do servidor e variáveis $_SERVER quando APP_DEBUG=true.
config/app.phpagora forçaAPP_DEBUG=falsequandoAPP_ENV=production, independentemente do valor no.env.- Adicionado guard PHP no topo de
debug.phpque encerra com HTTP 500 seAPP_DEBUGnão estiver ativo — segunda camada de defesa. - Removidos
REMOTE_ADDReHTTP_USER_AGENTda tabela$_SERVERexibida na página de debug. .env.exampleatualizado comAPP_DEBUG=falsecomo padrão, com comentário de aviso explícito.
SESSION_SECURE forçado em produção (corrigido)
O .env.example vinha com SESSION_SECURE=false, o que permitia que o cookie de sessão fosse transmitido em HTTP puro em produção.
config/app.phpagora ativasession.cookie_secureautomaticamente quandoAPP_ENV=production, independentemente da variável do.env.- Adicionada variável
SESSION_SAME_SITEao.env.examplepara controle explícito.
exec() renomeado para execMigration() em Database (corrigido)
O método exec() aceitava SQL puro sem prepared statements e podia ser invocado em qualquer contexto da aplicação — uma porta para SQL Injection se usado indevidamente.
- Renomeado para
execMigration()com docblock de aviso explícito: DDL-only, nunca receba input de usuário. database/migrate.phpatualizado para chamarexecMigration().- Aviso expandido em
getPdo()sobre os riscos de acessar o objeto PDO diretamente.
✅ Funcionalidades Completadas
"Lembrar de mim" (implementação completa)
A funcionalidade existia como TODO na versão anterior — o token era gerado mas nunca persistido, tornando a opção completamente não funcional.
Implementação completa e segura:
- Token de 64 chars gerado com
random_bytes(32)(criptograficamente seguro). - Armazenado no banco como hash SHA-256 — o valor bruto nunca é persistido.
- Cookie enviado com
HttpOnly,SecureeSameSite=Lax. - Expiração de 30 dias.
- Token rotacionado a cada re-login — prevenção de token theft.
- Invalidado no logout (banco + cookie).
Auth::recoverFromCookie()chamado automaticamente no bootstrap para re-autenticação silenciosa.- Checkbox "Lembrar de mim" adicionado ao formulário de login.
Migration 002_add_rate_limit_table.sql adiciona as colunas remember_token e remember_token_expires_at na tabela users.
⚡ Melhorias Internas
bootstrap/app.phpagora chamaAuth::recoverFromCookie()automaticamente no início de cada requisição quando o cookie estiver presente.- Limpeza probabilística de cache de rate limit no bootstrap (sem cron externo).
Auth::buildSessionUser()usa reflection para ler$hiddendo Model dinamicamente — garante queremember_tokeneremember_token_expires_atnunca cheguem à sessão mesmo em Models customizados.AuthController::login()lê o checkboxrememberdo POST e repassa aoAuthService.AuthService::login()recebe e propaga o flag$rememberparaAuth::loginUser().
📦 Arquivos Alterados
app/Core/Auth.php
app/Core/Database.php
app/Controllers/AuthController.php
app/Services/AuthService.php
app/Middlewares/RateLimitMiddleware.php ← NOVO
app/Middlewares/SecurityHeadersMiddleware.php ← NOVO
app/Views/auth/login.php
app/Views/layouts/auth.php
app/Views/errors/debug.php
routes/web.php
config/app.php
bootstrap/app.php
database/migrate.php
database/migrations/002_add_rate_limit_table.sql ← NOVA
storage/cache/ratelimit/ ← NOVO diretório
.env.example
.gitignore
🔄 Guia de Atualização
# 1. Substituir os arquivos listados acima
# 2. Executar a nova migration
php database/migrate.php
# 3. Revisar o .env
# Confirmar: APP_DEBUG=false
# Em produção com HTTPS: SESSION_SECURE=trueNenhuma alteração é necessária em Controllers, Models ou Views existentes além dos listados.
🔄 Compatibilidade
- Compatível com projetos v1.1.X.
- Nenhuma quebra de compatibilidade na API pública do framework.
- A única alteração que exige ação é a execução da migration
002para adicionar as colunas de remember token.
📄 Licença
Distribuído sob os termos da GNU General Public License v3.0 (GPL-3.0).