SecureVault es una aplicación web full-stack con autenticación segura, control de roles, bitácoras de auditoría y una demostración controlada de secuestro de sesión. Está construida con Node.js, Express, PostgreSQL, sesiones persistidas con connect-pg-simple y una interfaz vanilla HTML/CSS/JavaScript con un tema oscuro creativo.
- Registro e inicio de sesión con
bcryptjsy validación de entrada. - Sesiones persistidas en PostgreSQL con regeneración tras login.
- Control de acceso basado en roles para usuario y administrador.
- Tres bitácoras independientes:
ACCESS_OK,ACCESS_FAILyLOGOUT. - Monitoreo de sesiones activas y sesiones sospechosas.
- Detección demostrativa de anomalías por cambio simultáneo de IP y User-Agent.
- Panel de administración con métricas, usuarios, logs y monitor de sesiones.
- Panel de usuario con detalles de sesión, copia del Session ID y actividad reciente.
- Tema oscuro/luminoso, toasts, reloj en vivo y animaciones visuales.
project-root/
├── server.js
├── package.json
├── .env.example
├── render.yaml
├── db/
│ ├── schema.sql
│ └── pool.js
├── middleware/
│ ├── auth.js
│ └── logger.js
├── routes/
│ ├── authRoutes.js
│ └── dashboardRoutes.js
├── public/
│ ├── css/style.css
│ ├── js/main.js
│ └── pages/
│ ├── index.html
│ ├── register.html
│ ├── admin.html
│ ├── user.html
│ └── 403.html
└── docs/
└── screenshots/
- Instala dependencias:
npm install-
Crea el archivo
.enva partir de.env.example. -
Configura PostgreSQL y ejecuta el esquema:
psql "$DATABASE_URL" -f db/schema.sqlEn Windows también puedes usar:
psql -h host -U user -d dbname -f db/schema.sql- Inicia la app:
npm start- Abre
http://localhost:3000.
- Sube el repositorio a GitHub.
- Conecta el repositorio a Render.com.
- Crea un nuevo Web Service apuntando al repo.
- Añade una base PostgreSQL gratuita.
- Configura
SESSION_SECRETyDATABASE_URL.
- Si usas el
render.yamlcomo Blueprint,SESSION_SECRETse genera automáticamente. - Si creaste el servicio manualmente, debes agregar
SESSION_SECRETen Variables de Entorno.
- Verifica que
render.yamlesté en la raíz del proyecto. - Ejecuta el esquema una sola vez con el endpoint protegido:
GET /setup?key=TU_SETUP_KEY
- Comprueba los logs del servicio y las bitácoras en
/api/admin/logs.
Esta demo está pensada para educación en seguridad. El objetivo es mostrar que una cookie de sesión robada puede permitir acceso si el sistema no detecta cambios de contexto.
- Inicia sesión como usuario en Chrome.
- Abre DevTools y ve a Application > Cookies.
- Copia el valor de
connect.sid. - Abre Firefox y entra a la URL de la app.
- Abre DevTools > Application > Cookies.
- Crea una cookie llamada
connect.sidcon el valor copiado. - Navega a
/user. - Observa si el acceso es aceptado o si aparece la alerta de anomalía.
- Revisa el panel de administración y abre Logs para ver la marca de actividad sospechosa.
Se registra cuando un login es exitoso. Incluye usuario, rol, IP, User-Agent, Session ID y timestamp.
Ejemplo:
ACCESS_OK | username=admin | role=admin | ip=127.0.0.1 | sessionId=abc123...
Se registra cuando falla el acceso por usuario inexistente, contraseña incorrecta o cuenta inactiva. No crea sesión.
Ejemplo:
ACCESS_FAIL | reason=WRONG_PASSWORD | username=demo | ip=127.0.0.1
Se registra al cerrar sesión desde /logout.
Ejemplo:
LOGOUT | username=demo | sessionId=abc123... | ip=127.0.0.1
users (1) ----< logs >---- (1) users
|
+----< session (connect-pg-simple)
users
- id, username, email, password, role, created_at, is_active
session
- sid, sess, expire
logs
- id, log_type, user_id, username, ip_address, user_agent, session_id, details, created_at
- Contraseñas hasheadas con
bcryptjsysaltRounds = 12. - Sesión regenerada tras login para evitar session fixation.
- Cookies
httpOnly,sameSite=laxysecureen producción. helmetpara cabeceras de seguridad.- Rate limit en
/loginde 5 intentos por IP cada 15 minutos. - Queries SQL parametrizadas en todas las rutas.
- Validación y sanitización de entradas en backend.
- CORS no habilitado por defecto.
- Verificación de rol en servidor para rutas protegidas.
- Sin exposición de stack traces en producción.
- Sesiones guardadas en PostgreSQL, no en memoria.
- Usuario:
admin - Correo:
admin@system.com - Contraseña:
Admin@12345
Cambia esta contraseña antes de usar la aplicación en producción.