llave-acceso
v1.0.5
Published
💡 **Nota importante:** Este sistema proporciona autenticación universal para todas las páginas de Tokenea, combinando login tradicional con tecnología Passkey y validación de sesiones del lado del servidor.
Readme
🔐 Sistema Universal de Login con Passkey - Tokenea
📋 Descripción General
💡 Nota importante: Este sistema proporciona autenticación universal para todas las páginas de Tokenea, combinando login tradicional con tecnología Passkey y validación de sesiones del lado del servidor.
🎯 Objetivo Principal
Crear un sistema de autenticación robusto y universal que:
- ✅ Proteja rutas automáticamente
- ✅ Combine login tradicional + Passkey
- ✅ Mantenga sesiones seguras del lado del servidor
- ✅ Redirija automáticamente a páginas protegidas tras login
- ✅ Sea fácil de implementar en cualquier página
🏗️ Arquitectura del Sistema
📦 Componentes Principales
| Componente | Archivo | Función |
|------------|---------|---------|
| Protector de Rutas | auto-auth.php | Verifica autenticación y redirige si es necesario |
| Página de Login | login.html | Interfaz de login con widget Passkey |
| Widget Passkey | passkey-auth.iife.js | Componente VITE+React para autenticación |
| Validador de Usuario | authenticateUser.php | Endpoint que valida credenciales |
🔄 Flujo de Autenticación
1. Usuario accede a página protegida
2. auto-auth.php se ejecuta automáticamente
3. ¿Sesión PHP válida?
- NO: Guarda URL original → Redirige a login.html
- SÍ: Continúa cargando página
4. En login.html: Usuario se autentica
5. Widget guarda datos en sessionStorage
6. Callback onPasskeyOk se ejecuta
7. Vuelve automáticamente a URL original⚙️ Implementación Paso a Paso
Paso 1: Proteger una Página ✅
Para proteger cualquier página, simplemente añade este código en el <head>:
<script>
window.redirectLogin = '/auth/login.html'; // URL de tu página de login
window.autoAuthConfig = {
storageType: 'sessionStorage',
storageKeys: {
session: 'tokenea_session',
user: 'tokenea_user',
originalUrl: 'tokenea_original_url'
},
debug: true
};
</script>
<!-- ✅ Auto-auth verificará y redirigirá si no está autenticado -->
<script src="/auth/auto-auth.php"></script>Paso 2: Configurar el Widget de Login ✅
El archivo login.html contiene la configuración del callback para retorno automático:
<script>
window.onPasskeyOk = (data) => {
console.log('Login exitoso:', data);
// ✅ Intentar volver a la URL original
setTimeout(() => {
const storage = sessionStorage;
const originalUrl = storage.getItem('tokenea_original_url');
if (originalUrl) {
console.log('Volviendo a URL original:', originalUrl);
storage.removeItem('tokenea_original_url');
window.location.href = originalUrl;
} else {
window.location.href = '/dashboard.html';
}
}, 100);
};
</script>🔒 Seguridad del Sistema
🛡️ Medidas de Seguridad Implementadas
- ✅ Validación del Servidor: Las sesiones se validan en PHP, no solo en JavaScript
- ✅ Directorio de Sesiones Personalizado:
/home5/sarbao/tokenea.com/sessions - ✅ Headers de Seguridad:
Cache-Control: no-cacheen auto-auth.php - ✅ Redirección Inmediata: Si no está autenticado, redirige antes de cargar contenido
- ✅ Limpieza de URLs Originales: Se eliminan tras uso para evitar loops
🔧 Configuración de Sesiones PHP
// En auto-auth.php
ini_set('session.save_path', '/home5/sarbao/tokenea.com/sessions');
session_start();
function isUserAuthenticated() {
return isset($_SESSION['tokenea_authenticated']) &&
$_SESSION['tokenea_authenticated'] === true &&
isset($_SESSION['tokenea_session']) &&
isset($_SESSION['tokenea_user']);
}📁 Estructura de Archivos
🗂️ Organización del Proyecto
/auth/
├── auto-auth.php # Protector universal de rutas
├── login.html # Página de login con widget
├── logout.php # Endpoint para cerrar sesión
└── authenticateUser.php # Validador de credenciales
/passkey/
├── passkey-auth.iife.js # Widget React compilado
└── [otros archivos del widget]
/sessions/ # Directorio de sesiones PHP
└── [archivos de sesión]🔧 Estado Actual del Desarrollo
✅ Completado
- ✅ auto-auth.php: Protector de rutas con validación PHP + JavaScript
- ✅ login.html: Página de login con callback de retorno
- ✅ Widget Passkey: Componente VITE+React funcionando
- ✅ Sesiones del Servidor: Migradas de cliente a servidor PHP
- ✅ Redirección Automática: Vuelve a URL original tras login
🔄 En Progreso
- 🔄 Conversión login.html → login.php: Para mayor seguridad del lado del servidor
- 🔄 Validación de Tokens: Verificación de expiración y validez
- 🔄 Headers de Seguridad: CSP, HSTS y otros headers de protección
📋 Pendiente
- ⏳ Logout Universal: Sistema de cierre de sesión en todas las páginas
- ⏳ Gestión de Errores: Manejo robusto de fallos de autenticación
- ⏳ Testing de Seguridad: Pruebas contra ataques comunes
- ⏳ Documentación API: Endpoints y configuraciones avanzadas
🚀 Próximos Pasos
Paso Inmediato: Conversión a login.php 🎯
💡 Objetivo: Convertir login.html en login.php para:
- Validar sesiones existentes del lado del servidor
- Aplicar headers de seguridad adicionales
- Prevenir acceso directo si ya está autenticado
- Mejorar la seguridad general del sistema
Consideraciones de Seguridad 🛡️
- Prevenir Renderizado Inicial: El contenido protegido no debe mostrarse ni por un instante
- Validación Doble: Cliente + Servidor para máxima seguridad
- Gestión de Errores: Manejo elegante de fallos de autenticación
- Limpieza de Datos: Eliminación segura de tokens expirados
📖 Uso Práctico
Ejemplo: Página Protegida Completa
<?php
// exploreitor.php - Ejemplo de página protegida
?>
<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8">
<title>Explorador Protegido</title>
<script>
window.redirectLogin = '/auth/login.html';
window.autoAuthConfig = {
storageType: 'sessionStorage',
storageKeys: {
session: 'tokenea_session',
user: 'tokenea_user',
originalUrl: 'tokenea_original_url'
},
debug: true
};
</script>
<!-- ✅ Auto-auth verificará y redirigirá si no está autenticado -->
<script src="/auth/auto-auth.php"></script>
</head>
<body>
<!-- Contenido protegido aquí -->
<h1>🔒 Área Protegida</h1>
<p>Solo usuarios autenticados pueden ver esto.</p>
</body>
</html>🎯 Resultado Esperado
- Usuario NO autenticado: Redirige inmediatamente a login.html
- Usuario autenticado: Muestra el contenido normalmente
- Tras login: Vuelve automáticamente a la página original
- Seguridad: Validación tanto en cliente como servidor
💡 Notas Técnicas
🔍 Debug y Troubleshooting
- Activar
debug: trueenautoAuthConfigpara logs detallados - Verificar que el directorio
/sessions/tenga permisos correctos - Comprobar que las URLs de login sean accesibles
- Validar que los endpoints del widget Passkey respondan correctamente
⚡ Optimizaciones
- El sistema usa
sessionStoragepor defecto (se borra al cerrar pestaña) - Cambiar a
localStoragesi se desea persistencia entre sesiones - Los headers
Cache-Control: no-cacheevitan cacheo de auto-auth.php - La redirección PHP es inmediata, antes de enviar JavaScript al cliente
📝 Conclusión
Este sistema de login universal proporciona una base sólida para la autenticación en Tokenea, combinando la comodidad de Passkey con la seguridad de validaciones del lado del servidor. La implementación actual permite proteger cualquier página con solo 2 líneas de configuración, manteniendo un flujo de usuario fluido y seguro.
El próximo paso crítico es la conversión de login.html a login.php para completar la migración hacia un sistema totalmente validado del lado del servidor, eliminando cualquier posible vulnerabilidad del lado del cliente.
📅 Documento generado: Sistema Universal de Login - Tokenea v1.0
🎯 Vectores de Ataque Posibles
1. 🚫 Intento de Bypass de auto-auth.php
¿Qué podría intentar?
// Hacker intenta en consola del navegador:
window.stop(); // Detener carga de scripts
// O modificar el DOM antes de que se ejecute auto-auth✅ ¿Por qué NO funciona?
auto-auth.phpse ejecuta DEL LADO DEL SERVIDOR antes de enviar HTML- El contenido HTML nunca llega al navegador si no está autenticado
- La redirección es PHP header redirect, no JavaScript
2. 🔧 Manipulación de JavaScript del Cliente
¿Qué podría intentar?
// En herramientas de desarrollador:
window.redirectLogin = null;
// O interceptar y modificar auto-auth.php response✅ ¿Por qué NO funciona?
- La validación REAL está en el servidor PHP
- Aunque modifique el JavaScript,
$_SESSION['tokenea_authenticated']sigue siendofalse - El contenido protegido nunca se envía desde el servidor
3. 🌐 Acceso Directo a Archivos
¿Qué podría intentar?
# Intentar acceder directamente sin auto-auth:
curl https://tokenea.com/dashboard.html
# O intentar acceder a archivos estáticos⚠️ VULNERABILIDAD REAL
Si dashboard.html es un archivo estático, podría accederse directamente.
🔧 Solución: Convertir a dashboard.php
<?php
require_once 'auth/auto-auth.php';
// Resto del contenido
?>4. 🍪 Ataques a Sesiones PHP
¿Qué podría intentar?
- Session Hijacking: Robar cookie de sesión
- Session Fixation: Forzar ID de sesión conocido
- Acceso directo: Leer archivos de
/sessions/
✅ Protecciones actuales:
// En auto-auth.php - Mejorar con:
ini_set('session.cookie_httponly', 1);
ini_set('session.cookie_secure', 1);
ini_set('session.use_strict_mode', 1);
session_regenerate_id(true); // Regenerar ID tras login5. 🔐 Ataques al Sistema Passkey
¿Qué podría intentar?
- Phishing: Crear sitio falso para capturar credenciales
- Man-in-the-Middle: Interceptar comunicación
✅ ¿Por qué es casi imposible?
- FIDO2 verifica el origen del dominio
- Las claves privadas nunca salen del dispositivo
- Criptografía asimétrica resistente a interceptación
🛡️ Fortalezas del Sistema Actual
✅ Validación Dual (Cliente + Servidor)
graph LR
A[Cliente] --> B[Passkey Auth]
B --> C[Servidor PHP]
C --> D[Validación Sesión]
D --> E[Contenido Protegido]✅ Contenido Nunca Expuesto
- El HTML protegido no se envía si no hay sesión válida
- Diferente a sistemas que cargan todo y luego ocultan con JavaScript
⚠️ Vulnerabilidades Reales a Corregir
1. Archivos Estáticos Accesibles
# PROBLEMA: Si dashboard.html es estático
wget https://tokenea.com/dashboard.html # ¡Podría funcionar!
# SOLUCIÓN: Convertir a PHP
mv dashboard.html dashboard.php2. Configuración de Sesiones Mejorada
// En auto-auth.php - Añadir:
ini_set('session.cookie_httponly', 1); // No accesible desde JS
ini_set('session.cookie_secure', 1); // Solo HTTPS
ini_set('session.cookie_samesite', 'Strict'); // Prevenir CSRF
ini_set('session.use_strict_mode', 1); // IDs seguros3. Headers de Seguridad CSP
// Prevenir inyección de scripts
header("Content-Security-Policy: script-src 'self' 'unsafe-inline' cdn.jsdelivr.net");
header("X-Frame-Options: DENY");
header("X-Content-Type-Options: nosniff");🚨 Escenario de Ataque Más Realista
Un hacker experimentado podría:
- Análisis de red: Interceptar tráfico para entender el flujo
- Ingeniería social: Engañar al usuario para que comparta sesión
- Vulnerabilidades del servidor: Explotar fallas de Apache/PHP
- Acceso físico: Usar dispositivo desbloqueado del usuario
Pero NO podría:
- ❌ Generar sesiones válidas sin autenticación real
- ❌ Bypassear la validación del servidor
- ❌ Romper la criptografía FIDO2
🎯 Recomendaciones de Seguridad
📋 Inmediatas:
- [ ] Convertir archivos
.htmla.phpcon auto-auth incluido - [ ] Mejorar configuración de sesiones con headers seguros
- [ ] Implementar CSP headers para prevenir XSS
🚀 Avanzadas:
- [ ] Rate limiting en
authenticateUser.php - [ ] Logging de intentos de acceso no autorizado
- [ ] Monitoreo de sesiones anómalas
🔒 Conclusión
El sistema actual es bastante seguro gracias a la validación del lado del servidor y la robustez de FIDO2. Las vulnerabilidades principales están en la configuración más que en el diseño arquitectónico.
Es un sistema de autenticación universal súper elegante:
La idea genial es:
Con solo incluir una línea de script en cualquier página, ya está protegida automáticamente Si no estás logueado, te redirige al login pero RECUERDA dónde estabas Después del login, te devuelve exactamente donde querías ir Todo validado del lado del servidor (PHP) para seguridad real El flujo es perfecto:
Usuario intenta entrar a /dashboard.html auto-auth.php se ejecuta y pregunta: "¿Tienes sesión válida?" Si NO → Guarda la URL original y redirige a login Usuario se loguea con Passkey El callback onPasskeyOk lee la URL guardada ¡BOOM! Te lleva de vuelta a /dashboard.html automáticamente Lo brillante del sistema:
Para el desarrollador: Solo una línea protege cualquier página Para el usuario: Flujo natural, siempre vuelve donde quería ir Para la seguridad: Validación real del servidor, no solo JavaScript Ahora estamos en el punto de convertir login.html a login.php para que también el login sea validado del lado del servidor, ¿verdad? Así cerramos el círculo de seguridad completo.
