/home/suroeste/public_html/payments.transportessuroeste.com/src/Middleware
Edit: /home/suroeste/public_html/payments.transportessuroeste.com/src/Middleware/SecurityMiddleware.php (9705B)
setSecurityHeaders();
$this->validateRequest();
$this->detectSuspiciousPatterns();
}
/**
* Establecer headers de seguridad
*/
private function setSecurityHeaders(): void
{
// Prevenir clickjacking
header('X-Frame-Options: DENY');
// Prevenir MIME sniffing
header('X-Content-Type-Options: nosniff');
// XSS Protection
header('X-XSS-Protection: 1; mode=block');
// Referrer Policy
header('Referrer-Policy: strict-origin-when-cross-origin');
// Content Security Policy
header("Content-Security-Policy: default-src 'self'; script-src 'self' 'unsafe-inline' https://checkout.epayco.co; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; connect-src 'self' https://api.epayco.co https://checkout.epayco.co;");
// Strict Transport Security (solo en producción con HTTPS)
if (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') {
header('Strict-Transport-Security: max-age=31536000; includeSubDomains');
}
// Cache control para APIs
header('Cache-Control: no-store, no-cache, must-revalidate, max-age=0');
header('Pragma: no-cache');
// Tipo de contenido
header('Content-Type: application/json; charset=utf-8');
}
/**
* Validar la petición
*/
private function validateRequest(): void
{
// Validar método HTTP
$allowedMethods = ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'];
if (!in_array($_SERVER['REQUEST_METHOD'], $allowedMethods)) {
throw new SecurityException('Método HTTP no permitido', 405);
}
// Validar Content-Type para POST/PUT
if (in_array($_SERVER['REQUEST_METHOD'], ['POST', 'PUT'])) {
$contentType = $_SERVER['CONTENT_TYPE'] ?? '';
// Permitir form-data para callbacks de ePayco
$isFormData = strpos($contentType, 'application/x-www-form-urlencoded') !== false ||
strpos($contentType, 'multipart/form-data') !== false;
$isJson = strpos($contentType, 'application/json') !== false;
// Solo validar si hay body
$body = self::getRequestBody();
if (!empty($body) && !$isJson && !$isFormData) {
// Permitir si es callback de ePayco (sin Content-Type correcto a veces)
$uri = $_SERVER['REQUEST_URI'] ?? '';
if (strpos($uri, 'callback') === false && strpos($uri, 'webhook') === false) {
throw new SecurityException('Content-Type debe ser application/json', 415);
}
}
}
// Validar tamaño del body
$contentLength = $_SERVER['CONTENT_LENGTH'] ?? 0;
$maxSize = 1024 * 1024; // 1MB
if ($contentLength > $maxSize) {
throw new SecurityException('Payload demasiado grande', 413);
}
}
/**
* Detectar patrones sospechosos
*/
private function detectSuspiciousPatterns(): void
{
$uri = $_SERVER['REQUEST_URI'] ?? '';
$userAgent = $_SERVER['HTTP_USER_AGENT'] ?? '';
$body = self::getRequestBody();
// Patrones de SQL Injection
$sqlPatterns = [
'/(\bunion\b.*\bselect\b)/i',
'/(\bselect\b.*\bfrom\b)/i',
'/(\binsert\b.*\binto\b)/i',
'/(\bdelete\b.*\bfrom\b)/i',
'/(\bdrop\b.*\btable\b)/i',
'/(\bexec\b|\bexecute\b)/i',
'/(\'|\").*(--)/',
'/(\bor\b|\band\b).*(\b1\b\s*=\s*\b1\b)/i'
];
foreach ($sqlPatterns as $pattern) {
if (preg_match($pattern, $uri) || preg_match($pattern, $body)) {
LogService::security('sql_injection_attempt', 'Posible SQL Injection detectado', [
'uri' => $uri,
'ip' => LogService::getClientIp()
]);
throw new SecurityException('Solicitud bloqueada por seguridad', 403);
}
}
// Patrones de XSS
$xssPatterns = [
'/