FOLIO: AUD-20260926-040 Secuencia: Auditoría #4 del día 2026-09-26
📅 2026-09-26 13:45:00 COT 👤 Auditor: Anderson Mares (AMR TECH) ● VIGENTE

AMR TECH™ Security Audit

StreamingApps by AMR TECH

Auditoría Admin Panel Tienda

admin-amrtech.php + dashboard-amrtech.php

PHP / Admin Panel PDO / MariaDB 2 Críticos 6 Medios 7 Fortalezas

Revisión completa del panel de administración — autenticación, seguridad de sesiones, lógica TOTP 2FA, validaciones de entrada, monolito del dashboard y brechas operacionales en producción.

Score General

8.0 /10
Seguridad 9.2
Mantenibilidad 6.5
Observabilidad 4.0
Ops / Operacional 5.5

Veredicto

Componente más robusto del sistema

Listo para producción con correcciones críticas

1,485

Líneas admin-amrtech.php

1,634

Líneas dashboard-amrtech.php

2

Hallazgos Críticos

6

Hallazgos Medios

Resumen Ejecutivo

Este es el componente más sólido del sistema. La implementación de seguridad es excelente: bcrypt para contraseñas, rate limiting en login (5 intentos / 300s), TOTP 2FA, tokens de sesión con random_bytes(), hash_equals() para comparación resistente a timing-attack y prepared statements en toda la capa de datos. El panel admin es de calidad producción.

Las brechas son principalmente en observabilidad (sin audit log) y features operacionales faltantes (sin exportación, sin timeout de sesión, sin enforcement de 2FA). Los 2 hallazgos críticos están en la lógica de validación del SCRAPER_TOKEN.

Crítico

SCRAPER_TOKEN vacío = bypass auth. Reset de password con el mismo token vulnerable.

Medio

Sin audit log, sin exportación, 2FA no forzado, sin timeout de sesión, monolito 1634 líneas.

Excelente

bcrypt, rate limiting, random_bytes(), hash_equals(), TOTP 2FA, prepared statements — industria estándar.

Hallazgos Críticos SEVERITY: CRITICAL

C1

SCRAPER_TOKEN — Bypass de Autenticación por Token Vacío

admin-amrtech.php · Línea 243

🔴 CRÍTICO CVE-class: Auth Bypass

Si SCRAPER_TOKEN no está definido en el .env, la condición cortocircuita y permite paso sin autenticación. El catálogo completo queda expuesto a reset no autorizado.

Código Vulnerable (actual)

// Línea 243 — admin-amrtech.php if (SCRAPER_TOKEN === '' || !hash_equals(SCRAPER_TOKEN, $token)) { // ❌ Si token vacío → condición TRUE // pero lógica no retorna error aquí // → continúa ejecución del catálogo }

Corrección Recomendada

// Fix propuesto if (SCRAPER_TOKEN === '') { http_response_code(500); die('SCRAPER_TOKEN not configured'); } if (!hash_equals(SCRAPER_TOKEN, $token)) { http_response_code(401); die('Unauthorized'); }
Impacto: Cualquier petición POST al endpoint de reset de catálogo puede ejecutarse sin credencial válida si la variable de entorno no está configurada. En un servidor recién desplegado o con .env incompleto, el endpoint queda abierto públicamente.
C2

Password Reset — Verificación con Token Reutilizado y Vulnerable

admin-amrtech.php · Líneas 257–280

🔴 CRÍTICO CVE-class: Privilege Escalation

El flujo de reset de contraseña reutiliza SCRAPER_TOKEN como mecanismo de verificación — el mismo token expuesto en C1. No hay OTP por email, no hay token de tiempo limitado (time-bounded), ni enlace firmado. Quien conozca SCRAPER_TOKEN puede resetear la contraseña de cualquier usuario admin.

Flujo Actual

→ POST con token=SCRAPER_TOKEN + nuevo password
→ Verifica con hash_equals (reutiliza mismo token)
→ Sin límite de tiempo, sin usuario específico validado
→ Sin email OTP, sin enlace firmado con expiración

Flujo Recomendado

✓ Generar token de reset único por solicitud: random_bytes(32)
✓ Almacenar en DB con expires_at = NOW() + 15min
✓ Enviar por email al admin — nunca expuesto en API
✓ Invalidar token inmediatamente al ser usado
Impacto: Un atacante con acceso al .env o que haya interceptado el token puede tomar control permanente del panel admin sin necesitar la contraseña original. El token es estático y nunca expira.

Hallazgos Medios SEVERITY: MEDIUM

M1

Sin tabla de Audit Log

Ambos archivos — persistencia

Las acciones del admin (login, cambios de productos, modificaciones de usuarios) no tienen rastro forense persistido en base de datos. Si el sistema es comprometido, es imposible determinar qué cambió o cuándo.

Fix: Crear tabla admin_audit_log con campos: timestamp, admin_id, action, ip, data_before, data_after. Insertar en cada mutación.
M2

Sin funcionalidad de exportación

dashboard-amrtech.php — ops

No hay manera de exportar datos de ventas, inventario o clientes a CSV/Excel desde el panel. Operacionalmente esto fuerza consultas directas a DB o trabajo manual, aumentando riesgo de errores.

Fix: Endpoints de exportación CSV con fputcsv(), headers correctos de Content-Disposition y sanitización de datos.
M3

dashboard-amrtech.php — Archivo Monolítico (1,634 líneas)

dashboard-amrtech.php — maintainability

El dashboard mezcla queries a DB, lógica de negocio y HTML en un único archivo de 1,634 líneas. Esto dificulta el testing, genera mayor superficie de ataque y hace que cualquier refactor requiera cirugía completa del archivo.

Problema: Queries SQL inline mezcladas con HTML output
Problema: Lógica de negocio sin separación en clases/servicios
Fix: Extraer a clases PHP por dominio: ProductService, OrderService, UserService
M4

RBAC sin granularidad fina

admin-amrtech.php — access control

Los roles admin/super-admin existen ($_SESSION['admin_role']) pero no hay permisos granulares (leer sin editar, ver reportes sin modificar productos, etc.).

Fix: Tabla de permisos muchos-a-muchos: admin_role_permissions con bitmask o JSON de capacidades.
M5

2FA Opcional — No Forzado para Admins

admin-amrtech.php · lógica TOTP

TOTP solo se activa si el usuario tiene totp_secret configurado. Un admin puede operar sin 2FA indefinidamente si no completó el onboarding de TOTP.

Fix: Flag 2fa_required en DB + redirect obligatorio a pantalla de setup TOTP si no está enrollado.
M6

Sin timeout de sesión por inactividad

admin-amrtech.php — session management

Las sesiones persisten hasta logout explícito. Sin timeout por inactividad, una sesión abierta en un equipo desatendido permanece activa indefinidamente — riesgo físico real en accesos compartidos.

Fix propuesto: if (time() - $_SESSION['last_activity'] > 1800) { session_destroy(); redirect('/login'); }

Fortalezas de Seguridad — Implementación Excelente INDUSTRY STANDARD

Este componente tiene la implementación de seguridad más robusta del sistema — todas las siguientes prácticas son de nivel producción

bcrypt Password Hashing

PASSWORD_BCRYPT

Uso de password_verify() + password_hash($pwd, PASSWORD_BCRYPT). Estándar de industria — protege contra rainbow tables y fuerza bruta offline.

Rate Limiting en Login

5 intentos / 300s

rateLimit('admin_login_' . $clientIp, 5, 300) — Previene ataques de fuerza bruta y credential stuffing. Implementación por IP correcta.

Session Tokens Criptográficamente Seguros

random_bytes(16)

$sessionToken = bin2hex(random_bytes(16)) — CSPRNG de PHP. Imposible de predecir o clonar. Mucho mejor que uniqid().

Timing-Safe Token Comparison

hash_equals()

hash_equals($storedToken, $providedToken) — Previene timing-attacks donde un atacante mide microsegundos de respuesta para inferir caracteres del token.

TOTP 2FA implementado

RFC 6238

Implementación de autenticación de dos factores basada en tiempo. Compatible con Google Authenticator y Authy. Segundo factor real, no SMS (que es phisheable).

Prepared Statements en Toda la Capa DB

Anti-SQLi

Patrón $pdo->prepare() + execute([$params]) consistente en todo el código. Elimina por diseño el vector de SQL Injection — cero concatenación de strings en queries.

Role-Based Session Management

$_SESSION['admin_role']

Separación entre roles admin y super-admin almacenada en sesión. Verificación de rol en endpoints protegidos. Base sólida para extender a RBAC granular.

Plan de Remediación

P1 — INMEDIATO

Corregir lógica SCRAPER_TOKEN — Separar caso vacío del caso inválido

Si SCRAPER_TOKEN === '' → http_response_code(500); die(). Nunca permitir paso. Validar también en el endpoint de password reset que el token no puede ser la cadena vacía.

P2 — INMEDIATO

Reemplazar flujo de password reset con OTP por email time-bounded

Generar token único en DB (random_bytes(32)), almacenar con expires_at a 15 minutos, enviar por email. Invalidar inmediatamente al usar.

P3 — ESTA SEMANA

Implementar tabla admin_audit_log

Schema: id, timestamp, admin_id, action, entity_type, entity_id, ip_address, data_before JSON, data_after JSON. INSERT en cada mutación de productos, usuarios y órdenes.

P4 — ESTA SEMANA

Agregar session idle timeout (30 minutos)

Al inicio de cada request admin: if (time() - $_SESSION['last_activity'] > 1800) { session_destroy(); header('Location: /login'); exit; } + actualizar $_SESSION['last_activity'] = time();

P5 — PRÓXIMAS 2 SEMANAS

Forzar 2FA para todas las cuentas admin

Añadir campo totp_required TINYINT DEFAULT 1. Si admin no tiene totp_secret y totp_required=1, redirect obligatorio a pantalla de enrollment de TOTP antes de acceder al dashboard.

P6 — PRÓXIMAS 2 SEMANAS

Agregar exportación CSV para productos, órdenes y usuarios

Endpoint protegido (solo super-admin) con Content-Type: text/csv y Content-Disposition: attachment. Usar fputcsv() con sanitización. Registrar descarga en audit log.

P7 — BACKLOG

Refactorizar dashboard-amrtech.php en servicios PHP

Extraer a clases: ProductService, OrderService, UserService, ReportService. El archivo HTML template solo llama a métodos, sin lógica inline. Mejora testabilidad y reduce superficie de ataque.

admin-amrtech.php

Líneas de código 1,485
Autenticación bcrypt + TOTP + rate limit
SQL Injection Prepared statements
Session tokens random_bytes(16)
SCRAPER_TOKEN bug Crítico — Línea 243
Password reset Crítico — Líneas 257-280
Session timeout No implementado
2FA enforcement Opcional solamente

dashboard-amrtech.php

Líneas de código 1,634
Separación de concerns Monolítico
Queries SQL Prepared statements
Exportación de datos No existe
Audit log No existe
RBAC granular Solo 2 roles básicos
Testabilidad Difícil — sin clases/DI
IP Allowlist admin Opcional / No activo
AUD-20260926-040 · admin-amrtech.php · dashboard-amrtech.php · Score: 8.0 / 10 · 2026-09-26 13:45:00 COT

⚡ AMR TECH™ · Desarrollado / Auditado por Anderson Mares

Generado automáticamente por Claude Code Agent · StreamingApps Security Audit Suite v1.1.0