Checklist de Seguridad de APIs
Una checklist de seguridad essential para APIs: autenticación, autorización, validación de entrada, rate limiting, encriptación, logging y endurecimiento de despliegue.
Introducción
Las APIs son la columna vertebral de las aplicaciones modernas — y una superficie de ataque primaria. Esta checklist cubre los controles de seguridad esenciales que toda API debe implementar, desde autenticación hasta endurecimiento de despliegue.
1. Autenticación
Usa Autenticación Basada en Tokens Fuertes
# Malo: API keys pasadas en query strings (logueadas por proxies)
GET /data?api_key=abc123
# Bueno: Bearer tokens en header Authorization
GET /data
Authorization: Bearer eyJhbGciOiJIUzI1NiIs...
Implementa JWT de Forma Segura
import jwt
from datetime import datetime, timedelta
def create_access_token(user_id, secret, algorithm="HS256"):
payload = {
"sub": str(user_id),
"iat": datetime.utcnow(),
"exp": datetime.utcnow() + timedelta(minutes=15),
"jti": str(uuid.uuid4()) # ID único de token para revocación
}
return jwt.encode(payload, secret, algorithm=algorithm)
Checklist de Requisitos
- Usa HTTPS en todas partes (sin fallback HTTP)
- Los tokens expiran en 15 minutos o menos (access tokens)
- Refresh tokens expiran en 7-30 días con rotación
- Almacena tokens de forma segura (cookies HttpOnly para clientes browser)
- Rechaza tokens con firmas débiles (none, none256)
2. Autorización
Aplica el Principio de Mínimo Privilegio
# Malo: falta verificación de admin
def delete_user(user_id):
db.execute("DELETE FROM users WHERE id = %s", user_id)
# Bueno: verificar autorización antes de actuar
def delete_user(requesting_user, target_user_id):
if not requesting_user.has_role("admin"):
raise Forbidden("Rol admin requerido")
if requesting_user.id == target_user_id:
raise BadRequest("No puedes eliminarte a ti mismo")
db.execute("DELETE FROM users WHERE id = %s", target_user_id)
Checklist
- Autentica antes de autorizar (sin bypass de auth)
- Valida propiedad del recurso (usuario A no puede acceder datos de usuario B)
- Control de acceso basado en roles (RBAC) o atributos (ABAC)
- Denegar por defecto — permitir explícitamente, no confiar implícitamente
3. Validación de Entrada
Valida Todo
from pydantic import BaseModel, Field, validator
class CreateUserRequest(BaseModel):
email: str = Field(..., min_length=5, max_length=254)
password: str = Field(..., min_length=12, max_length=128)
@validator("email")
def validate_email(cls, v):
if "@" not in v:
raise ValueError("Formato de email inválido")
return v.lower().strip()
Checklist
- Valida tipo, longitud, formato y rango para cada entrada
- Rechaza campos inesperados (validación de esquema estricta)
- Sanitiza subidas de archivos (extensión, tipo MIME, límites de tamaño)
- Usa consultas parametrizadas (previene inyección SQL)
- Codifica salida para prevenir XSS
4. Rate Limiting
Previene Abuso
from flask_limiter import Limiter
limiter = Limiter(
key_func=lambda: request.headers.get("Authorization"),
default_limits=["100 per minute"]
)
@app.route("/api/login", methods=["POST"])
@limiter.limit("5 per minute")
def login():
...
Checklist
- Límites diferentes por endpoint (más estricto para auth, más laxo para lectura)
- Límites por usuario y por IP
- Retorna
429 Too Many Requestscon headerRetry-After - Loggea y alerta sobre violaciones repetidas
5. Encriptación
Datos en Tránsito
- TLS 1.2+ solamente
- Suites de cifrado fuertes (sin RC4, DES, MD5)
- Header HSTS para prevenir ataques de downgrade
- Certificate pinning para clientes móviles
Datos en Reposo
from cryptography.fernet import Fernet
key = Fernet.generate_key()
cipher = Fernet(key)
# Encriptar campos sensibles
ssn_encrypted = cipher.encrypt(b"123-45-6789")
decrypted = cipher.decrypt(ssn_encrypted)
Checklist
- TLS 1.2+ para toda comunicación de API
- Encripta datos sensibles en reposo (PII, credenciales, tokens)
- Hashea contraseñas con bcrypt/Argon2 (nunca MD5 o SHA1)
- Gestión segura de claves (KMS, HSM, o vault — no en código)
6. Manejo de Errores
No Filtrues Información
# Malo: expone detalles internos
except DatabaseError as e:
return {"error": str(e)} # revela esquema, estructura de queries
# Bueno: mensaje genérico al cliente, log detallado server-side
except DatabaseError as e:
logger.error("Error de base de datos", exc_info=e, extra={"request_id": request.id})
return {"error": "Error interno del servidor"}, 500
Checklist
- Mensajes de error genéricos a clientes
- Logs detallados server-side (con IDs de correlación)
- Formato de error consistente (RFC 7807 Problem Details)
- No expongas stack traces, rutas de archivos ni info del sistema
7. Logging y Monitoreo
Qué Loggear
| Evento | Datos a Loggear | Datos a Evitar |
|---|---|---|
| Autenticación | Éxito/fallo, timestamp, IP | Contraseñas, tokens |
| Fallas de autorización | Recurso, acción, usuario | Payload sensible |
| Hits de rate limit | Usuario/IP, endpoint | Cuerpo completo de request |
| Errores | Tipo de error, ID de request, endpoint | Stack traces en logs de cliente |
Checklist
- Loggea todos los intentos de autenticación (éxito y fallo)
- Alerta sobre patrones anómalos (IPs inusuales, picos de volumen)
- Retén logs para investigación de incidentes (30-90 días)
- Agregación centralizada de logs (SIEM o equivalente)
8. CORS y Headers
# Política CORS estricta
from flask_cors import CORS
CORS(app, origins=["https://app.example.com"], supports_credentials=True)
# Headers de seguridad
@app.after_request
def add_security_headers(response):
response.headers["X-Content-Type-Options"] = "nosniff"
response.headers["X-Frame-Options"] = "DENY"
response.headers["Content-Security-Policy"] = "default-src 'self'"
response.headers["Strict-Transport-Security"] = "max-age=31536000"
return response
Checklist
- Restringe CORS a orígenes conocidos (no
*con credentials) - Establece headers de seguridad en todas las respuestas
- Desactiva banners de versión del servidor (nginx, Apache, framework)
9. Endurecimiento de Despliegue
- Ejecuta API en red aislada (VPC, subnets privadas)
- Usa un Web Application Firewall (WAF)
- Mantén dependencias actualizadas (escaneo automatizado de vulnerabilidades)
- Desactiva endpoints y métodos HTTP no usados
- Ejecuta con usuario de sistema de mínimo privilegio (no root)
Errores Comunes
- Confiar en validación del lado del cliente (siempre valida server-side)
- Almacenar secretos en variables de entorno sin rotación
- Usar IDs predecibles (
/user/1,/user/2) sin verificaciones de autorización - Faltar límites de paginación (DoS vía
?limit=999999) - CORS configurado a
*en producción
Temas Avanzados
Escenario: Hardening de API REST para Produccion
Sistema: API REST Node.js, 50 endpoints, 100K usuarios
Objetivo: Checklist completo de seguridad API
Checklist de seguridad API (40 items):
Autenticacion:
[x] JWT con RS256 (no HS256)
[x] Expiracion de token: 15 min access, 7 dias refresh
[x] Refresh token rotation
[x] MFA para endpoints admin
[x] Rate limiting en login: 5 intentos -> lock 15 min
[x] No exponer token en URL
[x] Logout invalida token (Redis blacklist)
[x] Password policy: min 12 chars, complejidad
Autorizacion:
[x] RBAC: roles user/admin/super_admin
[x] Verificar ownership en cada request (anti-IDOR)
[x] Scope por recurso: user solo accede sus datos
[x] Denegar por defecto, permitir explicitamente
[x] No auto-increment IDs (usar UUID)
Input:
[x] Schema validation (Zod) en cada endpoint
[x] Limite de tamano de payload (max 1MB)
[x] Sanitizacion de strings (no HTML injection)
[x] Queries parametrizadas (anti-SQL injection)
[x] No eval/exec con input de usuario
[x] File upload: validar tipo, tamano, contenido
Output:
[x] No exponer stack traces en prod
[x] DTO mapping: no exponer campos internos
[x] Headers: X-Content-Type-Options, X-Frame-Options, CSP, HSTS
[x] No exponer version del server/framework
[x] Rate limiting global: 100 req/min por usuario
Transporte:
[x] TLS 1.3 obligatorio (no TLS 1.0/1.1)
[x] Redirect HTTP -> HTTPS
[x] HSTS: max-age=31536000; includeSubDomains
[x] Certificate pinning (mobile apps)
Configuracion:
[x] CORS: origin estricto, no wildcard
[x] NODE_ENV=production
[x] Secrets en Secrets Manager (no .env en prod)
[x] Helmet() configurado
[x] Compression con Brotli (no gzip para evitar BREACH)
Logging y monitoreo:
[x] Audit log de acciones criticas
[x] No logear secrets, passwords, tokens, PII
[x] Alertas de intentos de auth fallidos
[x] Alertas de rate limit excedido
[x] SIEM integration (ELK + alerting)
Dependencias:
[x] npm audit en CI (--audit-level=high)
[x] Dependabot/Snyk configurado
[x] Lockfile en repo (package-lock.json)
[x] License check en CI
CI/CD:
[x] SAST (semgrep) en pipeline
[x] DAST (OWASP ZAP) en staging
[x] Container scan (Trivy) en build
[x] Secret scan (git-secrets) en pre-commit
[x] Code review obligatorio (1 approver min)
Lecciones:
- 40 items es el minimo para produccion
- IDOR es #1: verificar ownership siempre
- Schema validation en cada endpoint, sin excepciones
- Audit log + alerting = deteccion temprana
- SAST + DAST + secret scan en CI es obligatorio
Como priorizo si tengo poco tiempo?
Empieza por autenticacion (JWT seguro + rate limiting), autorizacion (verificar ownership), input validation (Zod en cada endpoint) y TLS. Estos 4 cubren el 80% de vulnerabilidades. Despues agrega headers (helmet), audit log, y dependency scanning. Finalmente, SAST/DAST en CI. La seguridad es un proceso continuo, no un proyecto unico.
Preguntas frecuentes
¿Cómo empiezo con esto en un proyecto existente?
Empieza con una parte pequeña y aislada de tu codebase. Aplica los conceptos de esta guía a un módulo o servicio. Mide el impacto, luego expande a otras áreas.
¿Qué herramientas necesito?
Las herramientas mencionadas throughout esta guía se listan en cada sección. La mayoría son open-source y ampliamente adoptadas. Consulta los recursos relacionados para instrucciones de setup.
¿Cómo mido el éxito después de implementar esto?
Define métricas claras antes de empezar: benchmarks de rendimiento, tasas de error o indicadores de mantenibilidad. Compara antes y después. Itera basándote en datos, no en suposiciones.
Recursos Relacionados
Guía de Mejores Prácticas de Seguridad
Una Referencia Detallada de seguridad de aplicaciones: autenticación, autorización, validación de inputs, gestión de secretos y prevención de vulnerabilidades comunes.
GuideSeguridad de Aplicaciones Web (OWASP Top 10)
Una guía enfocada en desarrolladores sobre el OWASP Top 10: inyección, control de acceso roto, XSS, diseño inseguro, y cómo prevenir cada vulnerabilidad con ejemplos de código.
GuideGuía de Diseño de APIs REST
Una Referencia Detallada para diseñar APIs REST limpias, escalables y mantenibles.
RecipeImplementar Rate Limiting para APIs y Aplicaciones Web
Cómo proteger APIs y endpoints web del abuso usando estrategias de rate limiting token bucket, sliding window y fixed window con implementaciones en Redis y memoria.
RecipeImplementar firma de peticiones con HMAC
Asegura peticiones de API con firmas HMAC y autenticación AWS Signature v4 para integridad de mensajes a prueba de manipulaciones.
RecipeRate Limiting de APIs
Protege las APIs de abuso y asegura uso justo de recursos con token bucket, sliding window y leaky bucket.