✅ Buenas Prácticas y Secure Coding

Lección 6 de 6 — Cómo escribir código seguro desde el diseño hasta el despliegue.

1. Validación y Sanitización de Entradas

Nunca confíes en la entrada del usuario. Toda entrada externa debe ser validada y sanitizada antes de procesarse.

Validación (rechazar lo inválido)

Verificar que el dato cumple con el formato esperado antes de usarlo.

❌ Incorrecto

# PHP - Sin validación
$id = $_GET['id'];
$query = "SELECT * FROM usuarios WHERE id = $id";

✅ Correcto

# PHP - Validación estricta
$id = filter_input(INPUT_GET, 'id', FILTER_VALIDATE_INT);
if ($id === false || $id < 1) {
    die("ID inválido");
}
$query = "SELECT * FROM usuarios WHERE id = ?";

Sanitización (limpiar lo peligroso)

Eliminar o escapar caracteres peligrosos según el contexto de salida.

# Python - Sanitización para HTML (contra XSS)
import html
user_input = "<script>alert('XSS')</script>"
safe_output = html.escape(user_input, quote=True)
# Resultado: &lt;script&gt;alert('XSS')&lt;/script&gt;

# JavaScript - Sanitización
const safe = DOMPurify.sanitize(userInput);
💡 Regla de oro: Valida la entrada (rechaza lo malo), sanitiza la salida (escapa lo necesario). Usa siempre prepared statements para SQL.

2. Hash de Contraseñas con bcrypt

Nunca almacenes contraseñas en texto plano ni uses algoritmos rápidos como MD5/SHA-1. Usa funciones diseñadas para hash de contraseñas.

Bcrypt — el estándar actual

# Node.js con bcrypt
const bcrypt = require('bcrypt');
const saltRounds = 12;

async function registrar(password) {
    const hash = await bcrypt.hash(password, saltRounds);
    // Guarda 'hash' en la base de datos
    return hash;
}

async function verificar(password, hashAlmacenado) {
    const match = await bcrypt.compare(password, hashAlmacenado);
    return match;  // true o false
}

# Python con bcrypt
import bcrypt
password = b"MiContraseñaSegura123"
salt = bcrypt.gensalt(rounds=12)
hash = bcrypt.hashpw(password, salt)
# Verificar
bcrypt.checkpw(password, hash)  # True

Alternativas modernas

⚠️ No uses: MD5, SHA-1, SHA-256 (directos, sin salt), o algoritmos personalizados. Todos son demasiado rápidos para hash de contraseñas.

3. Logging y Monitoreo Seguro

Los logs son esenciales para detectar y responder a incidentes, pero mal manejados pueden exponer información sensible.

Qué registrar

Ejemplo con logging estructurado

# Python - Logging seguro
import logging
import json

logger = logging.getLogger("seguridad")
handler = logging.FileHandler("/var/log/app/audit.log")
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
handler.setFormatter(formatter)
logger.addHandler(handler)

# Bueno: registrar intento sin datos sensibles
logger.warning(f"Intento de login fallido - usuario: {username} - IP: {ip}")

# Malo: exponer la contraseña en logs
logger.error(f"Login fallido - usuario: {username} - password: {password}")  # ❌

Protección de logs

4. OWASP Cheat Sheet Series

OWASP proporciona guías de referencia rápida (Cheat Sheets) para las prácticas de seguridad más importantes.

Cheat Sheets esenciales

Cheat Sheet Descripción
SQL Injection Prevention Prepared statements, parametrización, escapes.
XSS Prevention Output encoding, Content Security Policy (CSP).
Password Storage bcrypt, Argon2, salt, pepper.
Authentication MFA, sesiones seguras, rate limiting.
Input Validation Whitelist vs blacklist, tipos de datos, rangos.
Content Security Policy Cabecera CSP para mitigar XSS.
Logging Qué y cómo registrar eventos de seguridad.

5. Principios Generales de Secure Coding

🔐 Checklist de Seguridad para Desarrolladores

📚 Recursos Adicionales

📌 Resumen Final del Curso

🎓 La seguridad es un proceso, no un producto. Sigue aprendiendo y mejorando.