Files
AutoBooking/docs/superpowers/specs/2026-05-30-security-design.md
T

8.8 KiB

AutoBooking Security — Diseño Opción B

Fecha: 2026-05-30
Estado: Aprobado por usuario
Alcance: Anti-spam, anti-ghost registrations, rate limiting, IP geolocation backup, documentos de conductor


1. Contexto y problema

AutoBooking es una plataforma de transporte en WordPress (autobooking.online). Los problemas identificados:

  • Cuentas fantasma: cualquier bot puede registrarse como conductor o pasajero sin verificación
  • Spam en chat: wp_autobooking_chat sin rate limiting
  • API Key de Google Maps expuesta en código fuente PHP y en HTML del frontend
  • GPS spoofeable: el plugin geo-restrict confía 100% en coordenadas enviadas por el cliente
  • Sin rate limiting en ningún endpoint REST ni en login/registro

Funcionalidades existentes que se preservan sin cambios:

  • Selección de rol al login (Snippets #15 + #18: after-loginchoose-role)
  • Páginas de registro con diseño Forminator
  • Plugin autobooking-roles v1.1.0 (roles driver, driver_pending, corporate_admin)
  • Todos los plugins de dashboard (driver, passenger, corporate, admin)

2. Arquitectura

Componentes nuevos

Componente Tipo Propósito
autobooking-security.php Plugin nuevo Central de seguridad: rate limiting, nonces, IP geo
wp_ab_rate_limits Tabla DB Registro de hits por IP/endpoint
wp_ab_blocked_ips Tabla DB IPs bloqueadas con TTL
wp_ab_driver_documents Tabla DB Documentos de conductor (licencia, seguro, foto)
hCaptcha en registro Hook Forminator Verificación anti-bot en registro de conductores

Componentes modificados

Componente Cambio
autobooking-admin-dashboard.php Mover GMAPS_KEY a wp_options; mostrar documentos pendientes en tab Conductores
autobooking-geo-restrict.php Agregar verificación de IP via ip-api.com con caché transient

3. Rate Limiting

Tabla wp_ab_rate_limits

id           BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY
ip           VARCHAR(45) NOT NULL
endpoint     VARCHAR(80) NOT NULL
hits         INT UNSIGNED NOT NULL DEFAULT 1
window_start DATETIME NOT NULL
KEY (ip, endpoint, window_start)

Tabla wp_ab_blocked_ips

id         BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY
ip         VARCHAR(45) NOT NULL UNIQUE
reason     VARCHAR(120) NOT NULL DEFAULT ''
blocked_at DATETIME NOT NULL
expires_at DATETIME NOT NULL
KEY (ip, expires_at)

Límites configurados

Endpoint / Acción Límite Ventana Bloqueo automático
Registro de usuario 5 intentos 60 min 24 h
wp_login_failed 10 fallos 15 min 2 h
POST /autobooking/v1/* 120 requests 1 min 30 min
Chat (write) 1 mensaje 2 seg 10 min

Implementación

  • Hook register_post → verificar IP antes de crear usuario
  • Hook wp_login_failed → contar fallos de login por IP
  • Filter rest_dispatch_request → contar requests REST por IP
  • Helper ab_sec_check_rate( $ip, $endpoint, $limit, $window_sec ) → bool
  • Helper ab_sec_block_ip( $ip, $reason, $hours ) → void
  • IPs en whitelist (configurables en tab CONFIG del admin dashboard) nunca se bloquean

4. Anti-Ghost Registration

Flujo de registro de conductor

1. Usuario llena formulario Forminator en /driver-registration/
2. hCaptcha valida (verificación server-side)
3. Rate limit: máx 5 registros / hora / IP
4. WordPress crea usuario con rol driver_pending
5. Email de confirmación enviado → cuenta inactiva hasta confirmar
6. Conductor sube 3 documentos desde /pending-driver/
7. Admin aprueba en dashboard → rol pasa a driver

hCaptcha

  • Servicio gratuito (hcaptcha.com) — requiere crear cuenta y obtener site key + secret key
  • Hook registration_errors para verificar h-captcha-response via POST https://api.hcaptcha.com/siteverify
  • Si falla → error visible en el formulario, registro rechazado
  • Site key y secret key guardadas en wp_options: ab_hcaptcha_site_key, ab_hcaptcha_secret

Email confirmation

  • Token de confirmación en wp_usermeta: ab_email_token (SHA256 random), ab_email_token_expires (24h)
  • Usuario con rol driver_pending sin email confirmado → redirigido a /pending-driver/ con mensaje "Confirma tu email"
  • Endpoint GET /autobooking/v1/confirm-email?token=xxx → valida token, marca ab_email_confirmed = 1
  • Si el token expiró (>24h): mostrar página "Token expirado" con botón para reenviar email de confirmación (endpoint POST /autobooking/v1/resend-confirmation)

Tabla wp_ab_driver_documents

id          BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY
driver_id   BIGINT UNSIGNED NOT NULL
doc_type    ENUM('license','insurance','vehicle_photo') NOT NULL
file_url    VARCHAR(512) NOT NULL DEFAULT ''
expiry_date DATE NULL
status      ENUM('pending','approved','rejected') NOT NULL DEFAULT 'pending'
reviewed_by BIGINT UNSIGNED NULL
reviewed_at DATETIME NULL
created_at  DATETIME NOT NULL
KEY (driver_id, doc_type)
KEY (status)

Regla de aprobación

  • Conductor sube docs desde /pending-driver/ — tipos permitidos: JPG, PNG, PDF (máx 5 MB por archivo), guardados en wp-content/uploads/ab-driver-docs/{user_id}/
  • Admin ve docs en tab CONDUCTORES → cola de aprobación
  • Botón "Aprobar conductor" solo habilitado si los 3 documentos existen
  • Rechazo envía email automático con motivo al conductor

5. IP Geolocation Backup

Modificación a /geo/check

1. Recibir lat/lng del cliente
2. Detectar país por bounding boxes (lógica existente — sin cambios)
3. Si país por GPS está en allowed list:
   a. Obtener IP del request (X-Forwarded-For validado, o REMOTE_ADDR)
   b. Si IP es privada/local (127.x, 10.x, 192.168.x) → confiar en GPS
   c. Consultar caché: transient "ab_geo_ip_{md5(ip)}" TTL=86400s
   d. Si no hay caché → llamar ip-api.com/json/{ip}?fields=countryCode
   e. Si ip-api.com falla (timeout/error) → fail open, permitir acceso
   f. Si país por IP != país por GPS → retornar allowed=false, mensaje "Ubicación inconsistente"
4. Retornar resultado normal
  • ip-api.com: gratuito, 45 req/min — el caché de 24h por IP lo mantiene muy por debajo del límite
  • El bloqueo por discrepancia es duro (no solo advertencia)

6. Google Maps API Key

Problema

const GMAPS_KEY = 'AIzaSyD3...' hardcodeada en autobooking-admin-dashboard.php:17 y expuesta en el HTML de la página de admin.

Solución en código

  • Eliminar la constante GMAPS_KEY
  • Leer siempre de get_option('ab_gmaps_key', '') — este campo ya existe en el tab CONFIG del admin dashboard
  • El campo ya estaba en la UI; solo hay que eliminar el fallback a la constante

Acción manual requerida (fuera del código)

  • Ir a Google Cloud Console → Credenciales → Restricciones de la key
  • Agregar restricción HTTP: solo *.autobooking.online/*

7. Modificaciones al Admin Dashboard

Tab CONDUCTORES

  • Columna "Docs" en cola de aprobación: muestra X/3 documentos subidos
  • Botón "Aprobar" deshabilitado si hay documentos faltantes
  • Modal muestra miniaturas de los 3 documentos con links para ver tamaño completo

Tab CONFIG — nueva sección "Seguridad"

  • Campo: IPs en whitelist (textarea, una por línea)
  • Tabla: IPs bloqueadas actualmente con columnas IP, Motivo, Expira, botón Desbloquear
  • Contador: intentos bloqueados en las últimas 24 h

8. Preservación de funcionalidad existente

Feature Estado Acción
Snippets #15 + #18 (choose-role) Sin cambios No tocar
Snippet #14 (login gating) Sin cambios No tocar
Snippet #19 (registro override) Sin cambios Solo agregar hCaptcha al hook
Páginas Forminator Sin cambios Solo agregar campo h-captcha-response
autobooking-roles plugin Sin cambios No tocar
Driver / Passenger / Corporate dashboards Sin cambios No tocar

9. Archivos a crear/modificar

CREAR:
  wp-content/plugins/autobooking-security/autobooking-security.php

MODIFICAR:
  wp-content/plugins/autobooking-admin-dashboard/autobooking-admin-dashboard.php
  wp-content/plugins/autobooking-geo-restrict/autobooking-geo-restrict.php

ACCIONES MANUALES:
  1. Google Cloud Console → restringir GMAPS_KEY a *.autobooking.online/*
  2. hcaptcha.com → crear cuenta gratuita, obtener site_key y secret_key
  3. Activar plugin autobooking-security desde WP Admin → Plugins

10. Criterios de éxito

  1. Un bot no puede crear más de 5 cuentas por hora desde la misma IP
  2. Un conductor nuevo no puede acceder al dashboard sin confirmar su email
  3. Un conductor no puede ser aprobado sin los 3 documentos subidos
  4. GPS de USA + IP de Rusia → bloqueado con mensaje claro
  5. La API Key de Google Maps no aparece en el HTML de ninguna página pública
  6. El flujo de selección de rol al login (choose-role) sigue funcionando sin cambios
  7. Las páginas de registro mantienen su diseño visual actual