Fundamentos de Ciberseguridad para Desarrolladores
Este mini-proyecto integra los conceptos clave de seguridad abordados en el curso, aplicándolos en una aplicación básica pero segura. La meta es crear una aplicación con los siguientes componentes:
- Autenticación y Autorización Segura: Implementación de autenticación usando tokens JWT.
- Cifrado de Datos en Tránsito y en Reposo: Uso de SSL/TLS y hashing para contraseñas.
- Validación y Sanitización de Entradas: Prevención de ataques de inyección.
- Monitoreo y Logging: Configuración de logs para actividades críticas y detección de patrones sospechosos.
Para este proyecto, puedes usar Node.js y Express como entorno de desarrollo.
Paso a Paso: Proyecto de Aplicación Segura
1. Configuración del Entorno
Crea una aplicación Express básica con Node.js:
mkdir secure-app
cd secure-app
npm init -y
npm install express jsonwebtoken bcryptjs dotenv winston
Configura las variables de entorno en un archivo .env:
JWT_SECRET=your_secret_key
2. Autenticación Segura con JWT
Crea el archivo auth.js para gestionar el inicio de sesión y generación de tokens JWT.
const jwt = require('jsonwebtoken');
const bcrypt = require('bcryptjs');
const users = [{ id: 1, username: 'user1', password: bcrypt.hashSync('password123', 8) }];
// Función de autenticación
function authenticate(username, password) {
const user = users.find(u => u.username === username);
if (user && bcrypt.compareSync(password, user.password)) {
const token = jwt.sign({ sub: user.id }, process.env.JWT_SECRET, { expiresIn: '1h' });
return { token };
}
throw 'Username or password is incorrect';
}
module.exports = { authenticate };
Crea una ruta de autenticación en tu aplicación para recibir credenciales y devolver un token si son válidas.
const express = require('express');
const { authenticate } = require('./auth');
const app = express();
app.use(express.json());
app.post('/login', (req, res) => {
try {
const { username, password } = req.body;
const { token } = authenticate(username, password);
res.json({ token });
} catch (error) {
res.status(401).send('Authentication failed');
}
});
3. Hashing Seguro para Contraseñas
- Usa bcrypt para almacenar contraseñas de forma segura.
- Asegúrate de hashear la contraseña antes de guardarla en la base de datos (en este caso, en el array
users).
const hashedPassword = bcrypt.hashSync('password123', 10);
4. Protección de Datos en Tránsito: Configuración de SSL/TLS
Genera un certificado SSL y configura HTTPS en tu servidor.
Puedes generar un certificado autofirmado para pruebas o usar Let’s Encrypt en producción.
Usa https en lugar de http al crear tu servidor:
const https = require('https');
const fs = require('fs');
const sslOptions = {
key: fs.readFileSync('path/to/private-key.pem'),
cert: fs.readFileSync('path/to/certificate.pem')
};
https.createServer(sslOptions, app).listen(3000, () => {
console.log('Secure server running on https://localhost:3000');
});
5. Validación y Sanitización de Entradas
Agrega una capa de validación para todas las entradas de los usuarios.
Utiliza la librería express-validator para validar y sanear la entrada en el servidor.
npm install express-validator
Ejemplo de validación en la ruta de login:
const { body, validationResult } = require('express-validator');
app.post('/login',
body('username').isAlphanumeric().withMessage('Username must be alphanumeric'),
body('password').isLength({ min: 6 }).withMessage('Password must be at least 6 characters'),
(req, res) => {
const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.status(400).json({ errors: errors.array() });
}
try {
const { username, password } = req.body;
const { token } = authenticate(username, password);
res.json({ token });
} catch (error) {
res.status(401).send('Authentication failed');
}
}
);
6. Monitoreo y Logging
Configura Winston para el manejo de logs:
const winston = require('winston');
const logger = winston.createLogger({
level: 'info',
format: winston.format.json(),
transports: [
new winston.transports.File({ filename: 'logs/error.log', level: 'error' }),
new winston.transports.File({ filename: 'logs/activity.log' })
]
});
module.exports = logger;
Registra eventos importantes como intentos de inicio de sesión en el archivo de actividad.
const logger = require('./logger');
app.post('/login', (req, res) => {
try {
const { username, password } = req.body;
const { token } = authenticate(username, password);
logger.info({
timestamp: new Date().toISOString(),
action: 'login',
user: username,
status: 'success'
});
res.json({ token });
} catch (error) {
logger.error({
timestamp: new Date().toISOString(),
action: 'login',
user: req.body.username,
status: 'failed'
});
res.status(401).send('Authentication failed');
}
});
Resumen
Este mini-proyecto cubre los conceptos principales de seguridad para una aplicación básica. Asegúrate de implementar cada componente de forma modular y revisarlo periódicamente para mejorar la seguridad y agregar nuevas capas de protección conforme a las necesidades de tu aplicación. Este proyecto también puede ampliarse a un sistema de producción, donde se pueden implementar controles adicionales, integraciones de auditoría, y monitoreo continuo para asegurar la protección de los datos y la estabilidad de la aplicación.