Almacenamiento en el Navegador
Persistencia de Datos en la Web
Agenda
- Mecanismos de almacenamiento disponibles
- Comparación detallada
- Cuándo usar cada uno
- Seguridad y mejores prácticas
- Ejemplos prácticos
localStorage
localStorage: Características
- Capacidad: 5-10 MB por origen
- Persistencia: Permanente (hasta limpieza manual)
- Alcance: Todas las pestañas/ventanas del mismo origen
- API: Síncrona y simple
- Tipo de datos: Solo strings
localStorage: Sintaxis Básica
// Guardar
localStorage.setItem('tema', 'oscuro');
localStorage.setItem('usuario', JSON.stringify({ nombre: 'Ana' }));
// Leer
const tema = localStorage.getItem('tema');
const usuario = JSON.parse(localStorage.getItem('usuario'));
// Eliminar
localStorage.removeItem('tema');
localStorage.clear();
localStorage: Casos de Uso
✅ Ideal para:
- Preferencias de usuario (tema, idioma)
- Configuraciones de UI
- Flags de features
- Estado de onboarding
❌ Evitar para:
- Tokens de autenticación
- Datos sensibles
- Datos con expiración automática
localStorage: Ventajas y Desventajas
Ventajas:
- ✅ API simple e intuitiva
- ✅ Persistencia a largo plazo
- ✅ Compatible con todos los navegadores
Desventajas:
- ❌ Vulnerable a XSS
- ❌ Solo almacena strings
- ❌ API síncrona (bloquea UI)
- ❌ Capacidad limitada (5-10 MB)
sessionStorage
sessionStorage: Características
- Capacidad: 5-10 MB por origen
- Persistencia: Solo durante la sesión de la pestaña
- Alcance: Solo la pestaña actual
- API: Idéntica a localStorage
- Isolamiento: Cada pestaña tiene su propio almacenamiento
sessionStorage: Casos de Uso
✅ Ideal para:
- Formularios multi-paso
- Carrito de compras temporal
- Estado de navegación dentro de sesión
- Tokens temporales
❌ Evitar para:
- Datos que deben persistir al cerrar pestaña
- Información compartida entre ventanas
sessionStorage vs localStorage
| Aspecto | localStorage | sessionStorage |
|---|---|---|
| Persistencia | Permanente | Solo sesión |
| Alcance | Todas las pestañas | Una pestaña |
| Se elimina | Manual | Al cerrar pestaña |
| Compartir datos | Entre pestañas | No |
Cookies
Cookies: Características
- Capacidad: ~4 KB por cookie
- Persistencia: Configurable (expires/max-age)
- Alcance: Configurable (domain, path)
- Enviadas automáticamente: Sí, en cada petición HTTP
- Acceso: Cliente y servidor
Cookies: Sintaxis Básica
// Cookie simple
document.cookie = "usuario=Ana";
// Con expiración (1 año)
document.cookie = "tema=oscuro; max-age=31536000";
// Con configuración completa
document.cookie = "sessionId=abc123; Secure; HttpOnly; SameSite=Strict; max-age=3600";
// Leer cookies
const cookie = document.cookie;
Cookies: Casos de Uso
✅ Ideal para:
- Autenticación (Session IDs con HttpOnly)
- Tokens CSRF
- Preferencias que necesita el servidor
- Analytics y tracking
❌ Evitar para:
- Grandes volúmenes de datos
- Datos que NO necesita el servidor
Cookies: Ventajas y Desventajas
Ventajas:
- ✅ Expiración automática configurable
- ✅ Se envían automáticamente con requests
- ✅ Atributos de seguridad (HttpOnly, Secure, SameSite)
- ✅ Soporte universal
Desventajas:
- ❌ Capacidad muy limitada (~4 KB)
- ❌ Se envían en TODAS las peticiones (overhead)
- ❌ API compleja de manejar en JavaScript
IndexedDB
IndexedDB: Características
- Capacidad: Cientos de MB a GB
- Persistencia: Permanente
- API: Asíncrona (eventos/promesas)
- Tipo de datos: Objetos, arrays, blobs, archivos
- Estructura: Base de datos NoSQL con índices
IndexedDB: Conceptos Clave
- Database: Contenedor principal
- Object Store: Tabla de datos
- Index: Para búsquedas eficientes
- Transaction: Operaciones ACID
- Cursor: Para iterar registros
IndexedDB: Abrir Base de Datos
const request = indexedDB.open("MiApp", 1);
request.onupgradeneeded = (event) => {
const db = event.target.result;
const store = db.createObjectStore("usuarios", {
keyPath: "id",
autoIncrement: true
});
store.createIndex("email", "email", { unique: true });
};
request.onsuccess = (event) => {
const db = event.target.result;
console.log("DB abierta");
};
IndexedDB: Operaciones CRUD
// Crear
const tx = db.transaction("usuarios", "readwrite");
const store = tx.objectStore("usuarios");
store.add({ nombre: "Ana", email: "ana@example.com" });
// Leer
const request = store.get(1);
request.onsuccess = () => console.log(request.result);
// Actualizar
store.put({ id: 1, nombre: "Ana García" });
// Eliminar
store.delete(1);
IndexedDB: Casos de Uso
✅ Ideal para:
- Progressive Web Apps (PWA)
- Almacenamiento offline de datos complejos
- Caché de grandes conjuntos de datos
- Aplicaciones que manejan archivos/blobs
❌ Evitar para:
- Datos simples clave-valor
- Necesidades de almacenamiento pequeño
IndexedDB: Ventajas y Desventajas
Ventajas:
- ✅ Gran capacidad (GB)
- ✅ API asíncrona (no bloquea UI)
- ✅ Soporta tipos de datos complejos
- ✅ Transacciones ACID
- ✅ Índices para búsquedas eficientes
Desventajas:
- ❌ API compleja y verbosa
- ❌ Curva de aprendizaje pronunciada
- ❌ Vulnerable a XSS
- ❌ Requiere gestión manual de versiones
Matriz de Decisión
¿Cómo elegir el mecanismo correcto?
¿Datos sensibles (tokens, passwords)?
├─ Sí → Cookies (HttpOnly + Secure + SameSite)
└─ No → ¿Cuánto espacio necesitas?
├─ < 4 KB → ¿El servidor lo necesita?
│ ├─ Sí → Cookies
│ └─ No → localStorage o sessionStorage
├─ 4 KB - 10 MB → localStorage o sessionStorage
└─ > 10 MB → IndexedDB
Matriz de Decisión (cont.)
¿Necesita persistir entre sesiones?
├─ Sí → localStorage, Cookies (con expires), IndexedDB
└─ No → sessionStorage
¿Requiere consultas complejas?
├─ Sí → IndexedDB
└─ No → Otros mecanismos
¿Es data del servidor?
├─ Sí → Cookies (se envía automáticamente)
└─ No → localStorage, sessionStorage, IndexedDB
Mejores Prácticas de Seguridad
Vulnerabilidades Principales
1. Cross-Site Scripting (XSS)
- Código malicioso inyectado puede leer localStorage/sessionStorage
- Puede acceder a IndexedDB
- Mitigación: Validar y sanitizar inputs
2. Cross-Site Request Forgery (CSRF)
- Uso no autorizado de cookies
- Mitigación: Atributo SameSite
3. Man-in-the-Middle (MITM)
- Interceptación de cookies sin Secure
- Mitigación: HTTPS + atributo Secure
Mejores Prácticas: Cookies
// ❌ MAL - Cookie insegura
document.cookie = "sessionId=abc123";
// ✅ BIEN - Cookie segura (desde servidor)
Set-Cookie: sessionId=abc123;
HttpOnly; // ❌ No accesible desde JS
Secure; // ✅ Solo HTTPS
SameSite=Strict; // ✅ Protección CSRF
Max-Age=3600; // ✅ Expira en 1 hora
Path=/;
Regla de oro: Los tokens sensibles SIEMPRE van en cookies con HttpOnly desde el servidor, NUNCA en localStorage.
Mejores Prácticas: IndexedDB
// ✅ BIEN - Manejo completo de errores
function guardarDatos(db, data) {
return new Promise((resolve, reject) => {
const tx = db.transaction('store', 'readwrite');
tx.onerror = () => reject(tx.error);
tx.oncomplete = () => resolve();
const store = tx.objectStore('store');
const request = store.add(data);
request.onerror = () => reject(request.error);
});
}
// ✅ BIEN - Versionado apropiado
const request = indexedDB.open('MiDB', 2);
request.onupgradeneeded = (event) => {
const db = event.target.result;
if (event.oldVersion < 2) {
// Migraciones de versión 2
}
};
Ejemplos Prácticos
Puntos Clave
- Elige según tus necesidades: No hay una solución única
- Seguridad primero: NUNCA datos sensibles sin protección
- HTTPS obligatorio: Imprescindible en producción
- localStorage ≠ Autenticación: Usa cookies HttpOnly
- IndexedDB para datos grandes: Cuando necesites > 10 MB
- Valida siempre: Todos los inputs del usuario
Arquitectura Recomendada
Para una aplicación moderna:
Autenticación → Cookies (HttpOnly + Secure + SameSite)
Preferencias → localStorage
Estado temporal → sessionStorage
Datos complejos → IndexedDB
Recursos Útiles
MDN Web Docs:
- Web Storage API
- IndexedDB
- Cookies
Web.dev:
- Storage for the web
- Security best practices
Herramientas:
- Chrome DevTools (Application tab)
- Firefox Storage Inspector
¿Preguntas?
Recuerda
- ✅ Seguridad primero
- ✅ Elige el mecanismo adecuado
- ✅ Prueba en diferentes navegadores
- ✅ Maneja errores apropiadamente
- ✅ Valida y sanitiza inputs
- ✅ Usa HTTPS en producción
Almacenamiento en el Navegador
By anlijudavid
Almacenamiento en el Navegador
- 29