# Análisis de Spam en Formularios - ROI Theme **Fecha de análisis:** 2026-01-08 **Problema:** Recepción de spam con datos aleatorios en formularios ## Características del Spam Detectado - **Nombres:** Cadenas aleatorias (ej: `kxUcwkDPHRAnUbdRWnDx`, `SOTbwKzTcZhJfTRBYSTV`) - **WhatsApp:** Cadenas aleatorias en lugar de números - **Emails:** Emails reales (posiblemente robados de bases de datos) - **Patrón:** Bots automatizados que llenan campos sin validación - **Fuente identificada:** `newsletter-footer` ## Módulos de Formularios Identificados ### Formulario 1: Newsletter Footer - **Handler**: `Public/Footer/Infrastructure/Api/WordPress/NewsletterAjaxHandler.php` - **Renderer**: `Public/Footer/Infrastructure/Ui/FooterRenderer.php` - **Acción AJAX**: `roi_newsletter_subscribe` - **Source en payload**: `newsletter-footer` ### Formulario 2: Contact Form (Sección + Modal) - **Handler**: `Public/ContactForm/Infrastructure/Api/WordPress/ContactFormAjaxHandler.php` - **Renderer**: `Public/ContactForm/Infrastructure/Ui/ContactFormRenderer.php` - **Acción AJAX**: `roi_contact_form_submit` - **Source en payload**: `contact-form` --- ## Hallazgos Durante la Revisión ### Archivos Identificados **Schemas:** - `Schemas/contact-form.json` **JavaScript (Frontend):** - `Assets/Js/footer-contact.js` - `Assets/Js/modal-contact.js` **PHP Backend - Newsletter (FUENTE DEL SPAM):** - `Public/Footer/Infrastructure/Api/WordPress/NewsletterAjaxHandler.php` - `Public/Footer/Infrastructure/Ui/FooterRenderer.php` --- ## Análisis del Formulario Newsletter (PRINCIPAL AFECTADO) ### Ubicación - **Handler AJAX**: `Public/Footer/Infrastructure/Api/WordPress/NewsletterAjaxHandler.php` - **Renderer HTML/JS**: `Public/Footer/Infrastructure/Ui/FooterRenderer.php` - **Fuente en payload**: `newsletter-footer` ✓ (coincide con spam reportado) ### Medidas de Seguridad EXISTENTES ✅ | Medida | Estado | Archivo | Línea | |--------|--------|---------|-------| | Nonce WordPress | ✅ Implementado | NewsletterAjaxHandler.php | 46 | | Rate Limiting (60s por IP) | ✅ Implementado | NewsletterAjaxHandler.php | 54-59 | | Sanitización de inputs | ✅ Implementado | NewsletterAjaxHandler.php | 62-64 | | Validación de email | ✅ Implementado | NewsletterAjaxHandler.php | 66 | | Webhook URL oculta | ✅ Implementado | Nunca expuesta al cliente | ### VULNERABILIDADES CRÍTICAS ❌ | Vulnerabilidad | Impacto | Prioridad | |----------------|---------|-----------| | **NO hay honeypot** | Bots pasan sin detección | 🔴 ALTA | | **NO hay CAPTCHA** | Sin verificación humana | 🔴 ALTA | | **NO hay validación de nombre** | Acepta `kxUcwkDPHRAnUbdRWnDx` | 🔴 ALTA | | **NO hay validación de WhatsApp** | Acepta `OGkrLENXqiQAaIYvCV` | 🔴 ALTA | | **Rate limiting débil** | 60s es poco, bots rotan IPs | 🟡 MEDIA | | **NO hay tiempo mínimo de envío** | Bots envían instantáneamente | 🟡 MEDIA | ### Campos del Formulario (FooterRenderer.php:336-343) ```html
``` ### Patrón del Spam Detectado Los datos de spam muestran: - **Nombres**: Cadenas alfanuméricas aleatorias (20+ caracteres) - **WhatsApp**: Cadenas alfanuméricas aleatorias (NO son números) - **Emails**: Emails reales (posiblemente de bases de datos filtradas) Esto indica **bots automatizados** que: 1. Bypassean la validación HTML5 (trivial) 2. Ignoran el rate limiting rotando IPs 3. Generan valores aleatorios para campos de texto 4. Usan emails reales para parecer legítimos --- ## Análisis del Formulario Contact Form (SEGUNDO FORMULARIO) ### Ubicación - **Handler AJAX**: `Public/ContactForm/Infrastructure/Api/WordPress/ContactFormAjaxHandler.php` - **Renderer**: `Public/ContactForm/Infrastructure/Ui/ContactFormRenderer.php` - **Schema**: `Schemas/contact-form.json` - **Fuente en payload**: `contact-form` ### Estado: ✅ ACTIVO (Clean Architecture) Este formulario está implementado correctamente con Clean Architecture: - Renderer genera HTML/CSS/JS dinámicamente - Handler AJAX procesa envíos server-side - Webhook URL guardada en BD (nunca expuesta al cliente) ### Medidas de Seguridad EXISTENTES ✅ | Medida | Estado | Archivo | Línea | |--------|--------|---------|-------| | Nonce WordPress | ✅ Implementado | ContactFormAjaxHandler.php | 47-48 | | Rate Limiting (30s por IP) | ✅ Implementado | ContactFormAjaxHandler.php | 55-61 | | Sanitización de inputs | ✅ Implementado | ContactFormAjaxHandler.php | 122-130 | | Validación de email | ✅ Implementado | ContactFormAjaxHandler.php | 151-155 | | Webhook URL oculta | ✅ Implementado | ContactFormAjaxHandler.php | 86 | ### VULNERABILIDADES CRÍTICAS ❌ | Vulnerabilidad | Impacto | Prioridad | |----------------|---------|-----------| | **NO hay honeypot** | Bots pasan sin detección | 🔴 ALTA | | **NO hay CAPTCHA** | Sin verificación humana | 🔴 ALTA | | **NO hay validación de nombre** | Acepta `kxUcwkDPHRAnUbdRWnDx` | 🔴 ALTA | | **NO hay validación de WhatsApp** | Acepta `OGkrLENXqiQAaIYvCV` | 🔴 ALTA | | **Rate limiting muy débil** | Solo 30s, bots rotan IPs | 🟡 MEDIA | | **NO hay tiempo mínimo de envío** | Bots envían instantáneamente | 🟡 MEDIA | ### Campos del Formulario (ContactFormRenderer.php:278-320) ```html
``` ### Nota sobre archivo Legacy (footer-contact.js) El archivo `Assets/Js/footer-contact.js` es **código legacy NO utilizado**: - NO está encolado en `Inc/enqueue-scripts.php` - Tiene webhook URL hardcodeada (mala práctica) - Fue reemplazado por el sistema Clean Architecture actual --- ## Resumen Comparativo de Ambos Formularios | Característica | Newsletter Footer | Contact Form | |----------------|-------------------|--------------| | **Estado** | ✅ ACTIVO | ✅ ACTIVO | | **Backend** | PHP AJAX | PHP AJAX | | **Nonce** | ✅ Sí | ✅ Sí | | **Rate Limit** | ✅ 60s | ✅ 30s | | **Sanitización** | ✅ Sí | ✅ Sí | | **Validación email** | ✅ is_email() | ✅ is_email() | | **Validación nombre** | ❌ Ninguna | ❌ Solo required | | **Validación WhatsApp** | ❌ Ninguna | ❌ Solo required | | **Honeypot** | ❌ NO | ❌ NO | | **CAPTCHA** | ❌ NO | ❌ NO | | **Tiempo mínimo** | ❌ NO | ❌ NO | ### Conclusión: AMBOS formularios comparten las MISMAS vulnerabilidades críticas --- ## Soluciones Anti-Spam Propuestas ### PRIORIDAD 1: Newsletter Footer (Urgente) #### 1.1 Honeypot Field (Implementación rápida, efectiva) ```html ``` Backend (`NewsletterAjaxHandler.php`): ```php // Verificar honeypot $honeypot = sanitize_text_field($_POST['website_url'] ?? ''); if (!empty($honeypot)) { // Es bot - responder éxito falso para no alertar wp_send_json_success(['message' => $successMsg]); return; } ``` #### 1.2 Validación de Contenido (Anti-gibberish) ```php // Validar nombre: solo letras, espacios, acentos $name = sanitize_text_field($_POST['name'] ?? ''); if (!empty($name) && !preg_match('/^[\p{L}\s\'-]{2,50}$/u', $name)) { wp_send_json_error(['message' => 'Nombre inválido'], 422); return; } // Validar WhatsApp: solo números, +, -, espacios $whatsapp = sanitize_text_field($_POST['whatsapp'] ?? ''); if (!empty($whatsapp) && !preg_match('/^[\d\s\+\-\(\)]{10,20}$/', $whatsapp)) { wp_send_json_error(['message' => 'Número de WhatsApp inválido'], 422); return; } ``` #### 1.3 Tiempo Mínimo de Envío ```php // En el formulario HTML agregar: // En el handler: $timestamp = (int) ($_POST['form_timestamp'] ?? 0); $minTime = 3; // segundos mínimos if (time() - $timestamp < $minTime) { // Envío demasiado rápido = bot wp_send_json_success(['message' => $successMsg]); // Falso éxito return; } ``` #### 1.4 Rate Limiting Mejorado ```php // Aumentar de 60s a 300s (5 minutos) // Y agregar límite diario por IP private function checkRateLimit(): bool { $ip = $this->getClientIP(); // Límite corto (5 minutos) $shortKey = 'roi_newsletter_short_' . md5($ip); if (get_transient($shortKey) !== false) { return false; } set_transient($shortKey, time(), 300); // Límite diario (máximo 5 por día) $dailyKey = 'roi_newsletter_daily_' . md5($ip); $dailyCount = (int) get_transient($dailyKey); if ($dailyCount >= 5) { return false; } set_transient($dailyKey, $dailyCount + 1, DAY_IN_SECONDS); return true; } ``` ### PRIORIDAD 2: Opciones Adicionales #### 2.1 Google reCAPTCHA v3 (Invisible) - Sin fricción para usuarios - Score basado en comportamiento - Requiere cuenta Google reCAPTCHA #### 2.2 Cloudflare Turnstile (Recomendado) - Gratuito - Sin tracking de Google - Más privado que reCAPTCHA #### 2.3 hCaptcha - Alternativa a reCAPTCHA - Mejor privacidad - Versión gratuita disponible --- ## Plan de Implementación ### Fase 1: Crear Servicio Anti-Spam Compartido 1. Crear `Shared/Infrastructure/Services/AntiSpamValidator.php` 2. Implementar validaciones reutilizables: - `validateHoneypot(string $value): bool` - `validateMinimumTime(int $timestamp, int $minSeconds = 3): bool` - `validateNameFormat(string $name): bool` (regex letras/espacios) - `validateWhatsAppFormat(string $phone): bool` (regex números) - `checkEnhancedRateLimit(string $ip, int $shortLimit, int $dailyLimit): bool` ### Fase 2: Aplicar a Newsletter Footer 1. Agregar honeypot + timestamp en `FooterRenderer.php` 2. Integrar AntiSpamValidator en `NewsletterAjaxHandler.php` 3. Probar que spam es rechazado ### Fase 3: Aplicar a Contact Form 1. Agregar honeypot + timestamp en `ContactFormRenderer.php` 2. Integrar AntiSpamValidator en `ContactFormAjaxHandler.php` 3. Probar que spam es rechazado ### Fase 4: Monitoreo y Mejoras (Opcional) 1. Agregar logging de intentos sospechosos 2. Evaluar CAPTCHA invisible si spam persiste 3. Dashboard de estadísticas anti-spam --- ## Archivos a Modificar ### Newsletter Footer | Archivo | Cambio | |---------|--------| | `Public/Footer/Infrastructure/Ui/FooterRenderer.php` | Agregar honeypot + timestamp oculto | | `Public/Footer/Infrastructure/Api/WordPress/NewsletterAjaxHandler.php` | Validaciones formato + honeypot check + rate limiting mejorado | ### Contact Form | Archivo | Cambio | |---------|--------| | `Public/ContactForm/Infrastructure/Ui/ContactFormRenderer.php` | Agregar honeypot + timestamp oculto | | `Public/ContactForm/Infrastructure/Api/WordPress/ContactFormAjaxHandler.php` | Validaciones formato + honeypot check + rate limiting mejorado | ### Código Reutilizable (Recomendado) Crear un trait o clase helper compartida para evitar duplicación: ``` Shared/Infrastructure/Services/AntiSpamValidator.php ``` - Validación de honeypot - Validación de tiempo mínimo - Validación de formato nombre (regex) - Validación de formato WhatsApp (regex) - Rate limiting mejorado --- ## Referencias Serena Las memorias existentes en `.serena/Memories/` documentan: - `diagnostico-estructura-carpetas-admin.md` - Estructura de carpetas Admin - `migracion-theme-options-tabla-personalizada.md` - Sistema de settings - `ROI_THEME_CSS_LOADING_ANALYSIS.md` - Análisis de carga CSS Esta memoria debe guardarse como referencia para implementación futura.