Seguridad y Middleware
Fox Framework proporciona un sistema completo y extensible de seguridad y middleware para proteger aplicaciones web y APIs. Esta documentación cubre todas las caracterÃsticas y opciones de seguridad disponibles.
CaracterÃsticas Principales
- Middleware de Seguridad: Protección contra ataques comunes
- Autenticación: Múltiples estrategias (JWT, OAuth, API Keys)
- Autorización: Control de acceso basado en roles y permisos
- CORS: Configuración detallada para comunicación cross-origin
- Encriptación: Utilidades para encriptar datos sensibles
- Rate Limiting: Protección contra ataques de fuerza bruta
- CSP: Content Security Policy para mitigar XSS
- AuditorÃa: Registro de actividad y eventos de seguridad
Middleware Básico
Creación de Middleware
import { Middleware, Request, Response, NextFunction } from '@foxframework/core';
// Middleware simple
const loggerMiddleware: Middleware = (req, res, next) => {
console.log(`${req.method} ${req.path}`);
next();
};
// Middleware con opciones
function corsMiddleware(options?: CorsOptions): Middleware {
return (req, res, next) => {
const origin = req.headers.origin;
// Aplicar configuración CORS según opciones
if (origin && options?.origins?.includes(origin)) {
res.setHeader('Access-Control-Allow-Origin', origin);
res.setHeader('Access-Control-Allow-Methods', options?.methods || 'GET,POST,PUT,DELETE');
res.setHeader('Access-Control-Allow-Headers', options?.headers || 'Content-Type,Authorization');
}
// Responder inmediatamente para solicitudes OPTIONS
if (req.method === 'OPTIONS') {
return res.status(204).end();
}
next();
};
}Aplicación de Middleware
import { FoxFactory, Router } from '@foxframework/core';
import { securityMiddleware } from '@foxframework/security';
// Crear router
const router = new Router();
// Middleware global (se aplica a todas las rutas)
router.use(loggerMiddleware);
router.use(securityMiddleware());
// Middleware en grupos de rutas
const apiRouter = new Router();
apiRouter.use(corsMiddleware({
origins: ['https://myapp.com'],
methods: 'GET,POST,PUT,DELETE',
headers: 'Content-Type,Authorization'
}));
// Middleware en rutas especÃficas
router.get('/admin/dashboard',
authMiddleware({ role: 'admin' }),
(req, res) => {
res.render('admin/dashboard');
}
);
// Encadenamiento de middleware
router.post('/api/documents',
authMiddleware(),
validateBody(documentSchema),
rateLimiter({ max: 10, windowMs: 60000 }),
async (req, res) => {
// Lógica del controlador
}
);
// Crear servidor con el router
const server = FoxFactory.createServer({
router,
port: 3000
});
server.start();Middleware de Seguridad
Fox Framework incluye un conjunto completo de middleware de seguridad para proteger aplicaciones:
Security Headers
import { securityHeaders } from '@foxframework/security';
router.use(securityHeaders({
// Prevenir que el navegador MIME-sniff la respuesta
noSniff: true,
// Habilitar la protección XSS del navegador
xssFilter: true,
// Prevenir clicjacking estableciendo X-Frame-Options
frameOptions: 'DENY', // o 'SAMEORIGIN'
// Habilitar HTTP Strict Transport Security
hsts: {
maxAge: 63072000, // 2 años en segundos
includeSubDomains: true,
preload: true
},
// Content-Security-Policy
contentSecurityPolicy: {
defaultSrc: ["'self'"],
scriptSrc: ["'self'", "'unsafe-inline'", 'trusted-cdn.com'],
styleSrc: ["'self'", "'unsafe-inline'", 'trusted-cdn.com'],
imgSrc: ["'self'", 'data:', 'trusted-cdn.com'],
connectSrc: ["'self'", 'api.myservice.com'],
fontSrc: ["'self'", 'fonts.googleapis.com', 'fonts.gstatic.com'],
objectSrc: ["'none'"],
mediaSrc: ["'self'"],
frameSrc: ["'none'"]
},
// Referrer-Policy
referrerPolicy: 'same-origin', // o 'strict-origin-when-cross-origin'
// Feature-Policy / Permissions-Policy
permissionsPolicy: {
camera: ['none'],
microphone: ['none'],
geolocation: ['self'],
payment: ['self'],
usb: ['none']
}
}));CORS (Cross-Origin Resource Sharing)
import { cors } from '@foxframework/security';
router.use(cors({
// OrÃgenes permitidos
origins: ['https://app.example.com', 'https://admin.example.com'],
// o usar '*' para permitir cualquier origen (no recomendado en producción)
// origins: '*',
// Métodos HTTP permitidos
methods: ['GET', 'POST', 'PUT', 'DELETE', 'PATCH'],
// Headers permitidos
allowHeaders: ['Content-Type', 'Authorization', 'X-Requested-With'],
// Headers expuestos al cliente
exposeHeaders: ['Content-Range', 'X-RateLimit-Limit'],
// Permitir enviar cookies en solicitudes cross-origin
credentials: true,
// Tiempo máximo para cachear el pre-flight
maxAge: 86400, // 24 horas
// Función para determinar origen dinámicamente
originValidator: (origin, req) => {
// Lógica personalizada para validar origen
return origin?.endsWith('.example.com') || false;
},
// Función para personalizar respuesta CORS
preflightHandler: (req, res) => {
// Personalizar respuesta OPTIONS
res.setHeader('X-CORS-Custom', 'Fox Framework');
}
}));CSRF Protection (Cross-Site Request Forgery)
import { csrfProtection } from '@foxframework/security';
// Configuración básica
router.use(csrfProtection({
// Nombre de la cookie que almacena el token
cookie: {
name: '_csrf',
httpOnly: true,
sameSite: 'strict',
secure: process.env.NODE_ENV === 'production'
},
// Nombre del campo en formularios/peticiones
fieldName: '_csrf',
// También se puede enviar en headers con este nombre
headerName: 'X-CSRF-Token',
// Duración del token
ttl: 86400, // 24 horas
// Rutas a excluir
ignorePaths: ['/api/webhook', '/public'],
// Métodos a proteger
safeMethods: ['GET', 'HEAD', 'OPTIONS'], // estos no requieren token
// Función para enviar error
onFailure: (req, res, next, error) => {
res.status(403).json({ error: 'Token CSRF inválido' });
}
}));
// En la vista (con pug/ejs/etc)
// <form action="/profile" method="post">
// <input type="hidden" name="_csrf" value="<%= csrfToken %>">
// <!-- resto del formulario -->
// </form>
// Incluir el token en la respuesta para SPA
router.get('/csrf-token', (req, res) => {
res.json({ csrfToken: req.csrfToken() });
});
// En el cliente JavaScript/SPA
// fetch('/api/data', {
// method: 'POST',
// headers: {
// 'Content-Type': 'application/json',
// 'X-CSRF-Token': csrfToken
// },
// body: JSON.stringify(data)
// });Rate Limiting
import { rateLimit } from '@foxframework/security';
// Limitar solicitudes por IP
router.use('/api', rateLimit({
// Número máximo de solicitudes permitidas
max: 100,
// Ventana de tiempo en milisegundos
windowMs: 15 * 60 * 1000, // 15 minutos
// Clave para identificar al cliente (por defecto es IP)
keyGenerator: (req) => req.ip,
// O usar una función personalizada para extraer identificador
// keyGenerator: (req) => req.headers['x-api-key'] || req.ip,
// Almacenamiento para contadores
// Por defecto usa memoria, pero se puede usar Redis u otro store
store: new RedisStore({
client: redisClient,
prefix: 'rl:'
}),
// Mensaje de error
message: 'Demasiadas solicitudes, por favor intenta más tarde',
// Código de estado
statusCode: 429,
// Headers en respuesta
headers: true, // incluir X-RateLimit-* headers
// Función para determinar si se debe saltar la limitación
skip: (req) => {
// Por ejemplo, no limitar para usuarios administradores
return req.user?.role === 'admin';
},
// Función para personalizar respuesta
handler: (req, res, next, options) => {
res.status(options.statusCode).json({
error: options.message,
retryAfter: Math.ceil(options.windowMs / 1000)
});
}
}));
// Diferentes lÃmites para diferentes rutas
router.post('/auth/login', rateLimit({
max: 5,
windowMs: 5 * 60 * 1000, // 5 minutos
message: 'Demasiados intentos de inicio de sesión'
}), authController.login);Helmet (Seguridad en Cabeceras HTTP)
import { helmet } from '@foxframework/security';
// Configuración completa
router.use(helmet({
// Content Security Policy
contentSecurityPolicy: {
directives: {
defaultSrc: ["'self'"],
scriptSrc: ["'self'", "'unsafe-inline'", 'cdn.jsdelivr.net'],
styleSrc: ["'self'", "'unsafe-inline'", 'cdn.jsdelivr.net'],
imgSrc: ["'self'", 'data:'],
fontSrc: ["'self'", 'fonts.gstatic.com'],
connectSrc: ["'self'", 'api.example.com'],
objectSrc: ["'none'"],
upgradeInsecureRequests: [],
},
},
// Cross-Origin-Embedder-Policy
crossOriginEmbedderPolicy: {
policy: 'require-corp'
},
// Cross-Origin-Opener-Policy
crossOriginOpenerPolicy: {
policy: 'same-origin'
},
// Cross-Origin-Resource-Policy
crossOriginResourcePolicy: {
policy: 'same-origin'
},
// Desactivar caracterÃsticas especÃficas
noSniff: true,
xssFilter: true,
dnsPrefetchControl: {
allow: false
},
// Strict-Transport-Security
hsts: {
maxAge: 15552000, // 180 dÃas
includeSubDomains: true,
preload: true
},
// Referrer Policy
referrerPolicy: {
policy: 'strict-origin-when-cross-origin'
},
// X-Frame-Options
frameguard: {
action: 'deny'
}
}));
// O usar configuración predeterminada
router.use(helmet());Autenticación
Fox Framework proporciona un sistema flexible para implementar diferentes estrategias de autenticación:
JWT (JSON Web Tokens)
import { jwtAuth } from '@foxframework/security';
// Configuración de JWT
const jwtMiddleware = jwtAuth({
// Clave secreta para firmar tokens
secretKey: process.env.JWT_SECRET_KEY,
// Algoritmo de firma
algorithm: 'HS256', // o RS256 para claves públicas/privadas
// Duración del token
expiresIn: '1d', // 1 dÃa
// Fuente del token (header, cookie, query)
tokenSource: {
header: 'Authorization', // Formato: "Bearer <token>"
headerFormat: 'Bearer', // Extraer con formato especÃfico
cookie: 'auth_token', // Nombre de cookie alternativa
query: 'token' // Parámetro de consulta alternativo
},
// Validación personalizada
verifyToken: async (decoded, req) => {
// Verificar si el usuario aún existe o está activo
const user = await userService.findById(decoded.sub);
if (!user || !user.active) {
return false;
}
// Añadir usuario al request
req.user = user;
return true;
},
// Manejo de errores
onError: (err, req, res, next) => {
if (err.name === 'TokenExpiredError') {
return res.status(401).json({ error: 'Token expirado' });
}
res.status(401).json({ error: 'No autorizado' });
}
});
// Aplicar a todas las rutas de API
router.use('/api', jwtMiddleware);
// Aplicar a rutas especÃficas
router.get('/api/protected', jwtMiddleware, (req, res) => {
res.json({ user: req.user });
});
// Generar token durante inicio de sesión
router.post('/auth/login', async (req, res) => {
const { email, password } = req.body;
try {
// Validar credenciales
const user = await userService.authenticate(email, password);
if (!user) {
return res.status(401).json({ error: 'Credenciales inválidas' });
}
// Generar token JWT
const token = jwt.sign(
{
sub: user.id,
name: user.name,
role: user.role
},
process.env.JWT_SECRET_KEY,
{ expiresIn: '1d' }
);
// Enviar token
res.json({
token,
user: {
id: user.id,
name: user.name,
email: user.email
}
});
} catch (error) {
res.status(500).json({ error: error.message });
}
});Autenticación con Sesiones
import { sessionAuth } from '@foxframework/security';
// Configuración de sesiones
const sessionMiddleware = sessionAuth({
// Clave secreta para firmar cookies de sesión
secret: process.env.SESSION_SECRET,
// Configuración de cookies
cookie: {
httpOnly: true,
secure: process.env.NODE_ENV === 'production',
maxAge: 24 * 60 * 60 * 1000, // 1 dÃa
sameSite: 'strict'
},
// Store para sesiones
store: new RedisStore({
client: redisClient,
prefix: 'sess:'
}),
// Prevenir ataques de fijación de sesión
resave: false,
// Ahorrar espacio no guardando sesiones vacÃas
saveUninitialized: false,
// Nombre de la cookie
name: 'fox.sid',
// Opciones para rolling sessions
rolling: true, // Renovar cookie en cada respuesta
// Función para cargar el usuario
loadUser: async (req) => {
if (req.session.userId) {
req.user = await userService.findById(req.session.userId);
}
}
});
// Aplicar middleware de sesión global
router.use(sessionMiddleware);
// Ruta de login
router.post('/auth/login', async (req, res) => {
const { email, password } = req.body;
try {
const user = await userService.authenticate(email, password);
if (!user) {
return res.status(401).json({ error: 'Credenciales inválidas' });
}
// Guardar ID de usuario en sesión
req.session.userId = user.id;
req.session.role = user.role;
res.json({
message: 'Login exitoso',
user: {
id: user.id,
name: user.name,
email: user.email
}
});
} catch (error) {
res.status(500).json({ error: error.message });
}
});
// Ruta de logout
router.post('/auth/logout', (req, res) => {
req.session.destroy((err) => {
if (err) {
return res.status(500).json({ error: 'Error al cerrar sesión' });
}
res.clearCookie('fox.sid');
res.json({ message: 'Sesión cerrada correctamente' });
});
});
// Middleware para proteger rutas
function requireAuth(req, res, next) {
if (!req.user) {
return res.status(401).json({ error: 'No autorizado' });
}
next();
}
router.get('/profile', requireAuth, (req, res) => {
res.json({ user: req.user });
});Autenticación con API Keys
import { apiKeyAuth } from '@foxframework/security';
// Configuración de API Keys
const apiKeyMiddleware = apiKeyAuth({
// Fuentes donde buscar la API key
sources: [
{ header: 'X-API-Key' },
{ query: 'api_key' }
],
// Función para validar la API key
validator: async (apiKey, req) => {
// Buscar la key en la base de datos
const keyData = await apiKeyService.findByKey(apiKey);
// Verificar si es válida
if (!keyData || !keyData.active) {
return false;
}
// Verificar si no ha expirado
if (keyData.expiresAt && new Date(keyData.expiresAt) < new Date()) {
return false;
}
// Guardar información asociada en el request
req.apiClient = {
id: keyData.clientId,
name: keyData.clientName,
permissions: keyData.permissions || []
};
return true;
},
// Manejo de errores
onError: (req, res) => {
res.status(401).json({
error: 'API key inválida o faltante'
});
}
});
// Aplicar a todas las rutas de API
router.use('/api', apiKeyMiddleware);OAuth 2.0 / OpenID Connect
import { oauth2Auth } from '@foxframework/security';
// Configuración OAuth2
const oauth2Middleware = oauth2Auth({
// Configuración del proveedor
provider: {
name: 'google',
authorizationURL: 'https://accounts.google.com/o/oauth2/auth',
tokenURL: 'https://oauth2.googleapis.com/token',
userInfoURL: 'https://www.googleapis.com/oauth2/v3/userinfo',
clientID: process.env.GOOGLE_CLIENT_ID,
clientSecret: process.env.GOOGLE_CLIENT_SECRET,
callbackURL: 'https://myapp.com/auth/google/callback',
scope: ['profile', 'email']
},
// Función para manejar el perfil del usuario
userProfileHandler: async (profile, tokens) => {
// Buscar usuario existente o crear uno nuevo
let user = await userService.findByEmail(profile.email);
if (!user) {
// Crear nuevo usuario
user = await userService.create({
email: profile.email,
name: profile.name,
avatarUrl: profile.picture,
authProvider: 'google',
authProviderId: profile.sub
});
}
return user;
},
// Opciones de sesión
session: {
create: true, // Crear sesión automáticamente
key: 'userId' // Clave en sesión para guardar ID de usuario
},
// Manejo de éxito
successRedirect: '/dashboard',
// Manejo de error
failureRedirect: '/login',
// Estado para prevenir CSRF
state: true
});
// Rutas de autenticación
router.get('/auth/google', oauth2Middleware.authorize());
router.get('/auth/google/callback', oauth2Middleware.callback());
// Ruta para iniciar sesión
router.get('/login', (req, res) => {
res.render('login', {
googleAuthUrl: oauth2Middleware.getAuthorizationUrl()
});
});Autorización
Fox Framework proporciona múltiples estrategias para implementar control de acceso basado en roles y permisos:
RBAC (Role-Based Access Control)
import { rbac } from '@foxframework/security';
// Definir roles y permisos
const rbacMiddleware = rbac({
// Definición de roles y permisos
roles: {
guest: {
permissions: ['read:public']
},
user: {
inherits: ['guest'],
permissions: ['read:own', 'write:own']
},
editor: {
inherits: ['user'],
permissions: ['read:any', 'write:any']
},
admin: {
inherits: ['editor'],
permissions: ['delete:any', 'manage:users']
}
},
// Función para obtener el rol del usuario
getUserRole: (req) => {
return req.user?.role || 'guest';
},
// Función para verificar la propiedad del recurso
resourceOwnership: async (req, permission) => {
if (!permission.includes(':own')) {
return true; // No se requiere verificar propiedad
}
const resourceId = req.params.id;
const userId = req.user?.id;
if (!resourceId || !userId) {
return false;
}
// Verificar si el recurso pertenece al usuario
const resource = await getResourceById(resourceId);
return resource?.userId === userId;
}
});
// Middleware para verificar permisos
function checkPermission(permission) {
return (req, res, next) => {
rbacMiddleware.can(req, permission)
.then(allowed => {
if (!allowed) {
return res.status(403).json({
error: 'No tienes permiso para realizar esta acción'
});
}
next();
})
.catch(next);
};
}
// Aplicar a rutas especÃficas
router.get('/posts/:id', checkPermission('read:any'), postController.getPost);
router.put('/posts/:id', checkPermission('write:own'), postController.updatePost);
router.delete('/posts/:id', checkPermission('delete:any'), postController.deletePost);
// Control de acceso en rutas de administración
router.use('/admin', checkPermission('manage:users'), adminRouter);ABAC (Attribute-Based Access Control)
import { abac } from '@foxframework/security';
// Configurar ABAC
const abacMiddleware = abac({
// PolÃticas de acceso
policies: {
// PolÃtica para editar post
'edit-post': {
// Función para evaluar la polÃtica
evaluate: async (context) => {
const { user, resource, action } = context;
// Administradores siempre pueden editar
if (user.role === 'admin') {
return true;
}
// Editores pueden editar cualquier post no publicado
if (user.role === 'editor' && !resource.published) {
return true;
}
// Usuarios normales solo pueden editar sus propios posts
if (user.role === 'user') {
return resource.authorId === user.id;
}
return false;
}
},
// PolÃtica para ver posts
'view-post': {
evaluate: async (context) => {
const { user, resource } = context;
// Posts publicados son públicos
if (resource.published) {
return true;
}
// Solo autor y administradores pueden ver posts no publicados
return user?.role === 'admin' || resource.authorId === user?.id;
}
}
},
// Función para obtener datos del usuario actual
getUserContext: (req) => {
return req.user || { role: 'guest' };
},
// Cargar recursos según el tipo y ID
getResource: async (req, resourceType) => {
if (resourceType === 'post') {
const postId = req.params.id;
return postService.findById(postId);
}
return null;
}
});
// Middleware para verificar polÃticas
function checkPolicy(policyName, resourceType) {
return async (req, res, next) => {
try {
const allowed = await abacMiddleware.check(req, {
policy: policyName,
resourceType,
action: req.method
});
if (!allowed) {
return res.status(403).json({
error: 'Acceso denegado según la polÃtica de seguridad'
});
}
next();
} catch (error) {
next(error);
}
};
}
// Aplicar a rutas
router.get('/posts/:id', checkPolicy('view-post', 'post'), postController.getPost);
router.put('/posts/:id', checkPolicy('edit-post', 'post'), postController.updatePost);Detección de Amenazas
Fox Framework incluye herramientas para detectar y prevenir amenazas de seguridad comunes:
XSS Protection (Cross-Site Scripting)
import { xssProtection } from '@foxframework/security';
// Configuración XSS
router.use(xssProtection({
// Sanitización de entrada
sanitizeInput: true,
// Sanitizar los siguientes campos
sanitizeFields: ['name', 'description', 'content', 'comment'],
// Opciones avanzadas
sanitizeOptions: {
allowedTags: ['h1', 'h2', 'p', 'a', 'ul', 'ol', 'li', 'b', 'i', 'strong', 'em'],
allowedAttributes: {
'a': ['href', 'target', 'rel'],
'*': ['class', 'id']
},
selfClosing: ['img', 'br', 'hr'],
allowedSchemesByTag: {
'a': ['http', 'https', 'mailto']
}
},
// Sanitizar cuerpo JSON
sanitizeBody: true,
// Sanitizar query params
sanitizeQuery: true,
// Sanitizar headers
sanitizeHeaders: ['user-agent', 'referer'],
// Respuesta XSS
setXSSHeaders: true
}));SQL Injection Prevention
import { sqlInjectionProtection } from '@foxframework/security';
// Configuración de protección contra SQL Injection
router.use(sqlInjectionProtection({
// Campos a monitorear
fields: ['search', 'query', 'filter', 'sort'],
// Patrones peligrosos
patterns: [
/(\b)(SELECT|INSERT|UPDATE|DELETE|DROP|ALTER)(\b)/i,
/(\b)(UNION|JOIN|OR|AND)(\s+)(SELECT)/i,
/--/,
/;/,
/\/\*/,
/\*\//
],
// Función para manejar detecciones
onDetection: (req, res, next, details) => {
console.error('Posible SQL Injection detectada:', details);
// Registrar el intento
securityLogger.warn('SQL Injection attempt', {
ip: req.ip,
path: req.path,
pattern: details.pattern,
value: details.value,
user: req.user?.id
});
// Responder con error
res.status(403).json({
error: 'Caracteres no permitidos en la consulta'
});
}
}));AuditorÃa y Logging
Security Audit Logging
import { securityAudit } from '@foxframework/security';
// Configuración del log de auditorÃa de seguridad
router.use(securityAudit({
// Eventos a registrar
events: {
// Autenticación
authentication: true, // Login, logout, fallos de autenticación
// Autorización
authorization: true, // Intentos de acceso denegados
// Cambios de datos sensibles
dataAccess: {
enabled: true,
resources: ['users', 'payments', 'settings']
},
// Cambios de configuración
configuration: true,
// Detección de amenazas
threats: true
},
// Niveles de detalle
detailLevel: 'high', // 'low', 'medium', 'high'
// Dónde guardar los logs
storage: {
// Consola
console: process.env.NODE_ENV !== 'production',
// Archivo
file: {
enabled: true,
path: './logs/security.log',
rotation: {
size: '10M',
interval: '1d',
maxFiles: 30
}
},
// Base de datos
database: {
enabled: true,
model: 'SecurityLog',
batchSize: 10, // Guardar en lotes para mejor rendimiento
ttl: 365 // dÃas de retención
},
// Servicio externo
remote: {
enabled: process.env.NODE_ENV === 'production',
url: process.env.SECURITY_LOG_SERVICE,
token: process.env.SECURITY_LOG_TOKEN,
batchInterval: 60000 // Enviar cada 1 minuto
}
},
// Enmascaramiento de datos sensibles
sensitiveFields: ['password', 'token', 'creditCard', 'ssn'],
// Incluir estos campos en cada log
includeFields: {
request: ['method', 'path', 'query', 'ip', 'headers.user-agent'],
response: ['statusCode'],
user: ['id', 'username', 'role']
}
}));
// Registrar eventos manualmente
router.post('/settings/update', (req, res) => {
try {
// Actualizar configuración
const result = settingsService.update(req.body);
// Registrar en auditorÃa
req.audit('settings.update', {
before: result.previousSettings,
after: result.newSettings,
importance: 'high'
});
res.json({ success: true });
} catch (error) {
res.status(500).json({ error: error.message });
}
});Encriptación y Manejo de Datos Sensibles
Encriptación de Datos
import { encryptionService } from '@foxframework/security';
// Inicializar servicio de encriptación
const encryption = encryptionService({
// Clave maestra para encriptación
masterKey: process.env.ENCRYPTION_MASTER_KEY,
// Algoritmo a usar
algorithm: 'aes-256-gcm', // Algoritmo recomendado
// Función para derivar claves
keyDerivation: {
iterations: 10000,
digest: 'sha512'
},
// Rotación de claves
keyRotation: {
enabled: true,
interval: '90d', // Rotar cada 90 dÃas
previousKeys: 2 // Mantener 2 claves anteriores para descifrado
}
});
// Ejemplo de uso
router.post('/users', async (req, res) => {
try {
const user = req.body;
// Encriptar datos sensibles
if (user.taxId) {
user.taxId = await encryption.encrypt(user.taxId);
}
if (user.phone) {
user.phone = await encryption.encrypt(user.phone);
}
// Guardar usuario
const result = await userService.create(user);
res.status(201).json({
id: result.id,
name: result.name,
email: result.email
});
} catch (error) {
res.status(500).json({ error: error.message });
}
});
// Descifrado
router.get('/users/:id', async (req, res) => {
try {
const user = await userService.findById(req.params.id);
// Desencriptar datos sensibles
if (user.taxId) {
user.taxId = await encryption.decrypt(user.taxId);
}
if (user.phone) {
user.phone = await encryption.decrypt(user.phone);
}
res.json(user);
} catch (error) {
res.status(500).json({ error: error.message });
}
});Password Hashing
import { passwordService } from '@foxframework/security';
// Inicializar servicio de contraseñas
const password = passwordService({
// Algoritmo para hash
algorithm: 'argon2id', // 'argon2id' o 'bcrypt'
// Opciones para Argon2id
argon2: {
memoryCost: 65536, // 64 MB
timeCost: 3, // 3 iteraciones
parallelism: 4 // 4 hilos
},
// Opciones para bcrypt
bcrypt: {
rounds: 12 // Factor de trabajo
},
// Opciones de pepper (secreto adicional)
pepper: {
enabled: true,
secret: process.env.PASSWORD_PEPPER,
encoding: 'hex'
}
});
// Crear hash
router.post('/auth/register', async (req, res) => {
try {
const { email, password: plainPassword, name } = req.body;
// Hash de contraseña
const passwordHash = await password.hash(plainPassword);
// Crear usuario
const user = await userService.create({
email,
password: passwordHash,
name
});
res.status(201).json({
id: user.id,
name: user.name,
email: user.email
});
} catch (error) {
res.status(500).json({ error: error.message });
}
});
// Verificar contraseña
router.post('/auth/login', async (req, res) => {
try {
const { email, password: plainPassword } = req.body;
// Buscar usuario
const user = await userService.findByEmail(email);
if (!user) {
return res.status(401).json({ error: 'Credenciales inválidas' });
}
// Verificar contraseña
const passwordMatch = await password.verify(plainPassword, user.password);
if (!passwordMatch) {
return res.status(401).json({ error: 'Credenciales inválidas' });
}
// Verificar si el hash necesita actualización
if (password.needsRehash(user.password)) {
// Generar nuevo hash y actualizar
const newHash = await password.hash(plainPassword);
await userService.updatePassword(user.id, newHash);
}
// Generar sesión/token
const token = await jwt.sign(
{ sub: user.id, email: user.email, role: user.role },
process.env.JWT_SECRET!,
{ expiresIn: '8h' }
);
res.json({
message: 'Login exitoso',
token,
usuario: { id: user.id, email: user.email, rol: user.role }
});
} catch (error) {
res.status(500).json({ error: error.message });
}
});Configuración de Seguridad para Entornos de Producción
Fox Framework proporciona herramientas para configurar correctamente la seguridad en entornos de producción:
import { FoxFactory, securityConfig } from '@foxframework/core';
import {
securityHeaders,
cors,
csrfProtection,
rateLimit,
sessionAuth,
securityAudit
} from '@foxframework/security';
// Crear configuración de seguridad para producción
const security = securityConfig({
// Entorno
environment: process.env.NODE_ENV,
// Claves secretas
secrets: {
session: process.env.SESSION_SECRET,
csrf: process.env.CSRF_SECRET,
jwt: process.env.JWT_SECRET
},
// Configuración CORS
cors: {
origins: [
'https://app.example.com',
'https://admin.example.com'
],
credentials: true
},
// Cabeceras de seguridad
headers: {
hsts: true,
noSniff: true,
xssFilter: true,
frameOptions: 'DENY',
contentSecurityPolicy: {
defaultSrc: ["'self'"]
// ...otras opciones CSP
}
},
// Prevención de amenazas
threatProtection: {
xss: true,
sqlInjection: true,
clickjacking: true
},
// Rate limiting
rateLimit: {
enabled: true,
maxRequests: 100,
timeWindow: 60 * 1000, // 1 minuto
whitelistedIPs: ['192.168.1.1']
},
// CSRF
csrf: {
enabled: true,
ignorePaths: ['/api/webhook', '/api/external']
},
// AuditorÃa
audit: {
enabled: true,
logPath: './logs/security',
detailLevel: 'high'
}
});
// Aplicar configuración de seguridad al servidor
const server = FoxFactory.createServer({
router: router,
port: process.env.PORT || 3000,
security: security
});
server.start();Mejores Prácticas de Seguridad
Fox Framework fomenta las siguientes mejores prácticas:
- Defense in Depth: Implementar múltiples capas de seguridad
- Principle of Least Privilege: Otorgar solo los permisos necesarios
- Fail Securely: Los errores no deben comprometer la seguridad
- Secure by Default: Configuraciones seguras por defecto
- Keep Security Simple: Evitar complejidad innecesaria
- Fix Security Issues Correctly: Resolver problemas correctamente, no solo sÃntomas
- Establish Secure Defaults: Establecer valores predeterminados seguros
- Positive Security Model: Permitir solo lo conocido como seguro
Resumen
El sistema de seguridad y middleware de Fox Framework proporciona herramientas completas para proteger aplicaciones web modernas:
- Headers de Seguridad: Protección contra ataques comunes
- Autenticación: Múltiples estrategias (JWT, OAuth, API Keys, sesiones)
- Autorización: Control de acceso basado en roles y atributos
- AuditorÃa: Registro detallado de eventos de seguridad
- Encriptación: Protección de datos sensibles
- Prevención: Mitigación de ataques XSS, CSRF, SQL Injection
Estas herramientas permiten a los desarrolladores implementar prácticas de seguridad robustas con configuración mÃnima, siguiendo los estándares y recomendaciones más recientes de la industria.