You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
interfaceJWT{header: {alg: 'HS256';typ: 'JWT';};payload: {sub: string;// ID del usuarioiat: number;// Fecha de emisiónexp: number;// Fecha de expiraciónrole: string;// Rol del usuario};signature: string;// Firma HMAC SHA-256}
Implementación
// Generación de tokenconstgenerateToken=(user: User): string=>{constpayload={sub: user.id,iat: Math.floor(Date.now()/1000),exp: Math.floor(Date.now()/1000)+(4*60*60),// 4 horasrole: user.role};returnjwt.sign(payload,process.env.JWT_SECRET,{algorithm: 'HS256'});};// Verificación de tokenconstverifyToken=(token: string): JWT=>{try{returnjwt.verify(token,process.env.JWT_SECRET)asJWT;}catch(error){thrownewUnauthorizedError('Token inválido');}};
constauthorize=(requiredPermissions: Permission[])=>{returnasync(req: Request,res: Response,next: NextFunction)=>{constuser=req.user;constuserPermissions=rolePermissions.get(user.role)||[];consthasPermission=requiredPermissions.every(permission=>userPermissions.includes(permission));if(!hasPermission){thrownewForbiddenError('No tiene permisos para realizar esta acción');}next();};};
// Uso de parámetros preparadosconstgetUserById=async(id: number): Promise<User>=>{returnawaitprisma.user.findUnique({where: { id }});};// Validación de tiposconstvalidateId=(id: unknown): number=>{if(typeofid!=='number'||isNaN(id)){thrownewBadRequestError('ID inválido');}returnid;};
Headers de Seguridad
// Middleware de headers de seguridadconstsecurityHeaders=(req: Request,res: Response,next: NextFunction)=>{res.setHeader('X-Frame-Options','SAMEORIGIN');res.setHeader('X-Content-Type-Options','nosniff');res.setHeader('X-XSS-Protection','1; mode=block');res.setHeader('Strict-Transport-Security','max-age=31536000; includeSubDomains');res.setHeader('Content-Security-Policy',"default-src 'self'");res.setHeader('Referrer-Policy','strict-origin-when-cross-origin');res.setHeader('Permissions-Policy','geolocation=()');next();};
Rate Limiting
// Configuración de rate limitingconstlimiter=rateLimit({windowMs: 15*60*1000,// 15 minutosmax: 100,// límite de 100 requests por ventanamessage: 'Demasiadas peticiones, por favor intente más tarde'});// Aplicar a rutas específicasapp.use('/api/auth',limiter);
Logging de Seguridad
// Logger de seguridadconstsecurityLogger=winston.createLogger({level: 'info',format: winston.format.json(),transports: [newwinston.transports.File({filename: 'security.log'})]});// Middleware de loggingconstsecurityLogging=(req: Request,res: Response,next: NextFunction)=>{constlogData={timestamp: newDate().toISOString(),ip: req.ip,method: req.method,path: req.path,userAgent: req.get('user-agent'),userId: req.user?.id};securityLogger.info('Request',logData);next();};