¿Qué Puede Salir Mal?
En automatización, los tres riesgos más comunes son:
| Vulnerabilidad | Ejemplo Real | Consecuencia |
|---|---|---|
| Secrets hardcodeados | API key de Telegram escrita en el código del Code Node | Si el workflow se exporta o comparte, la key queda expuesta |
| Webhook sin validación | POST público sin clave de autenticación | Cualquiera puede enviar datos falsos a tu sistema |
| Inyección de datos | Concatenar input del usuario en SQL o comandos | SQL injection, ejecución de comandos maliciosos |
Principio fundamental
Nunca confíes en el input externo. Todo dato que viene de un webhook, formulario o API es hostil hasta que lo validas. Tu workflow es la frontera.
Bandit — Auditoría de Código Python
Bandit es el analizador estático de seguridad más usado en Python. Escanea tu código en busca de patrones inseguros sin ejecutarlo, y te da un reporte de severidad.
# Instalar Bandit
pip install bandit
# Auditar una carpeta completa (recursivo)
bandit -r .
# Auditar un solo archivo
bandit script_automatizacion.py
# Solo mostrar las de severidad alta
bandit -r . -l
# Reporte en JSON (para integrar en CI)
bandit -r . -f json -o reporte_seguridad.json
Regla de oro del reporte
El objetivo no es "0 vulnerabilidades", es entender cada hallazgo: para cada issue de severidad HIGH debes poder explicar el vector de ataque y tu mitigación. Si no puedes, no está resuelto.
Vulnerabilidades que Bandit Detecta
| Hallazgo | Código Inseguro | Mitigación |
|---|---|---|
| Hardcoded password | password = "admin123" |
Usar variables de entorno o el sistema de credenciales de n8n |
| Command execution | os.system(cmd) con input del usuario |
Sanear entrada, usar subprocess con lista de argumentos |
| SQL injection | f-string en query SQL | Usar parámetros parametrizados ($1, $2 en n8n) |
| Pickle / deserialización | pickle.loads(datos) |
Evitar, o validar estrictamente la procedencia |
| Use of eval() | eval(input_usuario) |
Nunca. Reemplazar con parsing seguro |
Asegurar el Panel de n8n (Autenticación)
Si tu n8n está expuesto (aunque sea tras túnel), el panel debe pedir login. En n8n, las variables de entorno controlan esto:
| Variable | Función |
|---|---|
N8N_BASIC_AUTH_ACTIVE=true |
Activa el login con usuario y contraseña |
N8N_BASIC_AUTH_USER |
Usuario del panel (ej. gabriel) |
N8N_BASIC_AUTH_PASSWORD |
Contraseña fuerte (nunca la misma que en otros servicios) |
N8N_USER_MANAGEMENT_JWT_SECRET |
Clave JWT para sesiones (autogenerada en v2.x) |
N8N_ENCRYPTION_KEY |
Clave maestra para cifrar credenciales almacenadas |
Proteger un webhook con clave
Si expones un Webhook Trigger, exige una clave que solo tú conoces. El patrón más simple es exigir un header o query param en la URL:
// En tu workflow, primer nodo = IF que valida el header
{{ $json.headers['x-api-key'] === "tu_clave_secreta" }}
// El emisor debe incluir el header en cada POST
x-api-key: tu_clave_secreta
Error fatal
Una URL de webhook con clave en el query string (/hook/abc123?key=secret) se filtra en los logs del servidor y del cliente. Usa siempre un header, nunca un query param para secretos.
Checklist del Módulo 14
Desafío de Arquitecto
Audita tu Propio Código
- Escribe un script Python que simule la lógica de un Code Node (recibe JSON de webhook, ejecuta un comando
os.system, y usa una password hardcodeada). - Ejecuta
bandit -r .sobre la carpeta. - Registra los hallazgos de severidad HIGH y MEDIUM.
- Corrige cada uno: reemplaza el hardcode por
os.environ, elimina elos.systemcon input sin sanear, y parametriza cualquier consulta. - Re-ejecuta Bandit y confirma que los HIGH desaparecieron.
- Verifica también: tu panel de n8n tiene login activo y tu webhook exige header.