Node: Seguridad
Descubre cómo implementar medidas de seguridad en Node.js utilizando el módulo HTTP, cifrado de contraseñas, validación de datos y HTTPS. Configura tokens de acceso y protege tu proyecto ante amenazas comunes.
Aprende Node GRATIS y certifícateLa seguridad es una pieza clave en cualquier aplicación que maneje datos sensibles. A continuación, se describen las prácticas recomendadas para proteger servidores en Node.js, con un enfoque centrado en el uso de módulos nativos y librerías esenciales.
Creación de un servidor HTTP
Para comenzar, se puede utilizar el módulo http
de Node.js, que habilita la recepción de peticiones y la emisión de respuestas:
const http = require('http');
const servidor = http.createServer((req, res) => {
// Ejemplo de ruta principal
if (req.method === 'GET' && req.url === '/') {
res.writeHead(200, { 'Content-Type': 'text/plain' });
res.end('Servidor Node.js en marcha');
} else {
res.writeHead(404, { 'Content-Type': 'text/plain' });
res.end('Ruta no encontrada');
}
});
servidor.listen(3000, () => {
console.log('Servidor activo en http://localhost:3000');
});
Este servidor básico puede ampliarse con autenticación, validaciones y control de accesos, siempre manejando de forma cuidadosa los datos que llegan en cada solicitud.
Implementación de HTTPS
Para cifrar la comunicación entre cliente y servidor, se emplea el módulo https
, que requiere certificados SSL/TLS:
const https = require('https');
const fs = require('fs');
const opciones = {
key: fs.readFileSync('ruta/privkey.pem'),
cert: fs.readFileSync('ruta/cert.pem')
};
const servidorSeguro = https.createServer(opciones, (req, res) => {
res.writeHead(200);
res.end('Conexión segura en Node.js');
});
servidorSeguro.listen(443, () => {
console.log('Servidor HTTPS activo en el puerto 443');
});
Activar HTTPS protege los datos en tránsito y evita que sean interceptados o modificados.
Variables de entorno y configuración
Para gestionar claves o credenciales sensibles (por ejemplo, tokens secretos), se recomienda usar variables de entorno. Un archivo .env
puede contener valores como:
JWT_SECRET=clave-super-secreta
DB_PASSWORD=contraseña-segura
Con el paquete dotenv
, se importan al inicio de la ejecución:
require('dotenv').config();
// Acceso a las variables de entorno
const claveSecreta = process.env.JWT_SECRET;
Así, se evita exponer información sensible en el repositorio de código y se mantiene la configuración centralizada.
Manejo de contraseñas
Para cifrar contraseñas de usuarios, se suele usar bcrypt. Aplicar hashing y salt reduce el riesgo de que, ante un acceso no autorizado a la base de datos, se obtengan contraseñas en texto plano:
npm install bcrypt
const bcrypt = require('bcrypt');
async function cifrarContrasena(password) {
const saltRounds = 10;
return await bcrypt.hash(password, saltRounds);
}
async function verificarContrasena(password, hash) {
return await bcrypt.compare(password, hash);
}
Almacenar el hash en lugar de la contraseña real es un estándar de seguridad para cualquier sistema.
Autenticación con JSON Web Tokens
Para controlar el acceso de usuarios, se recurre a JWT. Con el paquete jsonwebtoken
se generan y validan tokens, que se pueden enviar en las cabeceras de cada petición:
npm install jsonwebtoken
const jwt = require('jsonwebtoken');
// Generar un token con información de usuario
function generarToken(usuarioId) {
return jwt.sign({ id: usuarioId }, process.env.JWT_SECRET, { expiresIn: '1h' });
}
// Verificar si un token es válido
function verificarToken(token) {
try {
const datos = jwt.verify(token, process.env.JWT_SECRET);
return datos;
} catch (error) {
return null;
}
}
Con este mecanismo, cada ruta de tu servidor puede comprobar el token antes de procesar la petición, reforzando la seguridad de los recursos.
Validación de datos
Controlar la información que los usuarios envían evita inyecciones o contenido malicioso. Una opción es usar la librería validator
, que aporta métodos para revisar formatos, como correos electrónicos y cadenas:
npm install validator
const validator = require('validator');
function esEmailValido(email) {
return validator.isEmail(email);
}
También es posible crear funciones personalizadas para verificar longitudes de cadenas, estructuras de JSON u otros requisitos específicos.
Control de acceso y rate limiting
Para evitar ataques de fuerza bruta, se puede imponer un límite de peticiones por IP. Una estrategia sencilla consiste en mantener un registro temporal de solicitudes y denegar acceso al sobrepasar un umbral determinado en un lapso de tiempo. Un ejemplo breve:
const mapaPeticiones = new Map();
const LIMITE_PETICIONES = 100;
const VENTANA_TIEMPO = 60 * 1000; // 1 minuto
function verificarLimite(ip) {
const tiempoActual = Date.now();
if (!mapaPeticiones.has(ip)) {
mapaPeticiones.set(ip, { conteo: 1, inicio: tiempoActual });
return true;
}
const registro = mapaPeticiones.get(ip);
if ((tiempoActual - registro.inicio) < VENTANA_TIEMPO) {
if (registro.conteo < LIMITE_PETICIONES) {
registro.conteo++;
return true;
}
return false;
} else {
registro.conteo = 1;
registro.inicio = tiempoActual;
return true;
}
}
En cada llamada entrante, se verifica la IP y se decide si permitir o bloquear el acceso. Este mecanismo refuerza la seguridad ante intentos masivos de acceder al servidor.
Manejo de errores y mensajes de respuesta
Para no exponer información interna, es conveniente responder con mensajes genéricos ante errores, registrando los detalles sensibles en un sistema de logs o en la consola. Un manejo responsable de excepciones impide a posibles atacantes obtener pistas sobre la infraestructura de la aplicación.
try {
// Operación que podría fallar
} catch (error) {
console.error('Error interno:', error);
// Responder con un código 500
}
Monitorización y auditoría
Mantener un ciclo de auditoría de dependencias con npm audit
o herramientas similares ayuda a corregir vulnerabilidades. También se aconseja actualizar periódicamente Node.js para aprovechar parches de seguridad y mejoras de rendimiento.
Asimismo, contar con un sistema de logs permite rastrear acciones sospechosas, detectar patrones de ataque y responder a incidentes con mayor precisión.
Lecciones de este módulo de Node
Lecciones de programación del módulo Seguridad del curso de Node.