Checklist de Seguridad API: Autenticación a Encriptación
Checklist de seguridad esencial para APIs: autenticación, autorización, validación de entrada, rate limiting, encriptación, logging y endurecimiento de despliegue.
Introducción
Tu API expone datos de 100.000 usuarios. Si falta un solo control de esta checklist, un atacante puede comprometerlos todos en menos de una hora. El OWASP API Security Top 10 lista la autorización de objetos rota como el riesgo #1 de 2023 — y es un arreglo de una línea que demasiados equipos omiten.
Esta checklist es la capa de verificación. Asume que ya tienes una API en producción (o a punto de publicarla) y necesitas confirmar que los controles de seguridad esenciales están en su lugar. Cada sección empareja una explicación breve con un patrón de código ejecutable y una checklist que puedes marcar. Para el análisis profundo de implementación de cualquier tema, consulta la Guía Completa de Seguridad de APIs.
La checklist cubre nueve familias de controles: autenticación, autorización, validación de entrada, rate limiting, encriptación, manejo de errores, logging, CORS/headers y endurecimiento de despliegue. Recórrelas en orden — las primeras cuatro cubren aproximadamente el 80% de las vulnerabilidades reales de APIs.
Cuándo Usar
Aplica esta checklist cuando:
- Estás a punto de publicar una API nueva en producción y necesitas una verificación de seguridad final.
- Heredaste una API existente sin controles de seguridad documentados.
- Tienes programada una prueba de penetración o auditoría de seguridad y quieres autoevaluarte primero.
- Estás revisando un pull request que toca autenticación, autorización o manejo de entrada.
- Estás endureciendo una API pública tras un incidente o vulnerabilidad reportada.
Esta checklist no es la herramienta adecuada cuando necesitas una arquitectura de seguridad desde cero — para eso está la Guía Completa de Seguridad de APIs. Tampoco cubre frameworks de cumplimiento (SOC 2, PCI DSS, HIPAA) — esos requieren su propio ejercicio de scoping. Si tu API es totalmente interna, aislada en una red privada sin exposición externa, muchos de estos controles siguen valiendo la pena, pero el orden de prioridad cambia.
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)
El mismo patrón en Node.js con jsonwebtoken:
const jwt = require("jsonwebtoken");
const crypto = require("crypto");
function createAccessToken(userId, secret) {
return jwt.sign(
{
sub: String(userId),
iat: Math.floor(Date.now() / 1000),
jti: crypto.randomUUID(),
},
secret,
{ algorithm: "HS256", expiresIn: "15m" }
);
}
La elección de algoritmo importa. HS256 (HMAC con secreto compartido) sirve para un solo servicio que emite y verifica sus propios tokens. En el momento en que un segundo servicio necesita verificar tokens, cambia a RS256 (firma RSA): el emisor guarda la clave privada, cada verificador usa la pública. Nunca aceptes alg: "none" — el algoritmo none fue un CVE real en varias librerías JWT y permite que cualquiera falsifique tokens.
El diagrama below muestra el flujo de rotación de access token / refresh token. El cliente nunca almacena el access token en localStorage — vive en una cookie HttpOnly. Cuando el access token expira, el cliente llama a /refresh con el refresh token, que se rota en cada uso para que un refresh token robado funcione exactamente una vez.
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)
- Usa RS256 (asimétrico) cuando más de un servicio verifica tokens
- Incluye un claim
jtipara poder revocar tokens vía denylist (Redis)
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)
Detén el IDOR Antes de que Llegue a Producción
Insecure Direct Object Reference (IDOR) es el riesgo #1 de API en el OWASP API Security Top 10. El bug es simple: el endpoint confía en el id de la URL sin verificar que el llamador es dueño de ese recurso. /api/orders/1234 devuelve la orden sin importar quién pregunta.
El arreglo es una línea de verificación de ownership en cada endpoint que recupera recursos:
# Malo: confía en el ID de la URL
order = db.get_order(request.args["id"])
return order
# Bueno: acota la consulta al usuario autenticado
order = db.get_order(id=request.args["id"], owner_id=request.user.id)
if order is None:
raise NotFound # 404, no 403, para evitar filtrar la existencia
Devolver 404 en lugar de 403 cuando un recurso existe pero no pertenece al llamador evita la enumeración — un atacante no puede distinguir “no existe” de “existe pero no es tuyo”.
Usa Identificadores Impredecibles
Los IDs secuenciales (/user/1, /user/2) permiten a los atacantes enumerar todos los registros simplemente incrementando el número en la URL. Si pasás a UUIDs (v4 o v7), el espacio de identificadores se vuelve demasiado grande para fuerza bruta — un atacante no puede adivinar /user/550e8400-e29b-41d4-a716-446655440000 probando números. Esto no reemplaza las verificaciones de autorización, pero te quita de encima un vector de ataque trivial.
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
- Devuelve 404 (no 403) para recursos que el llamador no posee, para evitar enumeración
- Usa UUIDs en lugar de IDs secuenciales para prevenir enumeración
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()
El equivalente en Node.js con Zod:
const { z } = require("zod");
const CreateUserRequest = z.object({
email: z.string().email().min(5).max(254).transform((v) => v.toLowerCase().trim()),
password: z.string().min(12).max(128),
role: z.enum(["user", "admin"]).default("user"),
}).strict(); // .strict() rechaza campos inesperados — previene mass assignment
La llamada .strict() es lo que detiene el mass assignment. Sin ella, una petición como {"email": "...", "password": "...", "role": "admin"} silenciosamente asigna el rol admin al usuario. Con modo estricto, el campo extra role se rechaza con un 400. El mass assignment es como ocurrieron varias tomas de control de cuenta de alto perfil — siempre elimina o rechaza campos que el cliente no debería controlar.
Checklist
- Valida tipo, longitud, formato y rango para cada entrada
- Rechaza campos inesperados (validación de esquema estricta — previene mass assignment)
- 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
- Define un tamaño máximo de payload (1 MB por defecto) para prevenir DoS vía cuerpos enormes
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():
...
Diferencia Límites por Sensibilidad del Endpoint
Un solo límite global rara vez es la elección correcta. Los endpoints de login y reseteo de contraseña necesitan límites estrictos (5 peticiones por minuto por IP) para ralentizar ataques de credential stuffing. Los endpoints de lectura pueden relajarse (100-1000 por minuto por usuario) porque un GET no modifica estado. Los endpoints de escritura necesitan un término medio — suficientemente estrictos para prevenir abuso, suficientemente holgados para no bloquear uso legítimo. La Guía de Diseño de API Gateway cubre cómo centralizar esto en la capa de gateway para que los servicios individuales no tengan que reimplementarlo cada uno.
El header Retry-After en una respuesta 429 no es opcional — sin él, los clientes bien comportados no pueden hacer backoff y martillearán el endpoint en un bucle de reintento ajustado. Los clientes mal comportados lo martillearán de todas formas, por eso el rate limiting se complementa con alertas: un pico repentino de 429s en una sola IP es una señal que vale la pena paginar.
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
- Aplica límites más estrictos a endpoints de login, reseteo de contraseña y signup
5. Encriptación
Datos en Tránsito
- TLS 1.2+ mínimo; prefiere TLS 1.3 para despliegues nuevos (handshake más rápido, menos round-trips)
- Suites de cifrado fuertes (sin RC4, DES, MD5, 3DES)
- Header HSTS para prevenir ataques de downgrade (
max-age=31536000; includeSubDomains) - Certificate pinning para clientes móviles (previene MITM vía CAs comprometidas)
El requisito de versión TLS es un objetivo móvil. TLS 1.0 y 1.1 están deprecados (RFC 8996) y deshabilitados por defecto en navegadores modernos. TLS 1.2 es el suelo actual; TLS 1.3 es el valor por defecto recomendado para APIs nuevas porque elimina suites de cifrado vulnerables y reduce el handshake de dos round-trips a uno.
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)
La llave de encriptación nunca debe vivir en código fuente, variables de entorno commiteadas a git, o archivos de configuración. Usa un servicio gestionado de llaves (AWS KMS, Google Cloud KMS, Azure Key Vault) o un secrets manager como HashiCorp Vault. Las llaves deben rotar en un calendario — anualmente como mínimo, inmediatamente ante cualquier exposición sospechada. Para el set completo de patrones — AES-256-GCM, cifrado envolvente y versionado de llaves por campo — mira la guía de cifrado en reposo.
Hashing de Contraseñas
Las contraseñas no se encriptan — se hashean, y el hash es unidireccional. El algoritmo importa:
| Algoritmo | Estado | Por qué |
|---|---|---|
| MD5, SHA1 | Nunca | Muy rápidos — miles de millones de intentos por segundo en una GPU |
| SHA256 (raw) | Nunca | También muy rápido para hashing de contraseñas |
| bcrypt | Aceptable | Factor de costo adaptable, probado en combate |
| Argon2id | Recomendado | Ganador del Password Hashing Competition, resistente a ataques GPU/ASIC |
| scrypt | Aceptable | Memory-hard, buena alternativa a Argon2 |
Checklist
- TLS 1.2+ para toda comunicación de API (prefiere 1.3 para despliegues nuevos)
- Encripta datos sensibles en reposo (PII, credenciales, tokens)
- Hashea contraseñas con bcrypt/Argon2id (nunca MD5 o SHA1)
- Gestión segura de claves (KMS, HSM, o vault — no en código)
- Rota llaves de encriptación anualmente o ante exposición sospechada
- Configura HSTS con
includeSubDomainsy unmax-agede al menos un año
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
Un mensaje de excepción crudo como duplicate key value violates unique constraint "users_email_key" le dice al atacante que la tabla se llama users y la columna es email. Eso es reconocimiento gratis. El cliente recibe un mensaje genérico; el log del lado del servidor guarda el detalle completo con un ID de correlación para que puedas rastrear la petición durante la respuesta a incidentes.
Usa un Formato de Error Consistente
El RFC 7807 define una forma JSON estándar para errores de API:
{
"type": "https://stackpractices.com/errors/forbidden",
"title": "Forbidden",
"status": 403,
"detail": "No tienes acceso a este recurso.",
"instance": "/api/orders/1234"
}
Los clientes pueden parsear el URI type para buscar documentación, y el campo instance te ayuda a correlacionar el error en tus logs. Esto supera a formas ad-hoc {"error": "..."} que varían por endpoint.
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
- Deshabilita el modo debug y las páginas de error verbosas en producción
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 |
El error más común de logging es escribir el cuerpo completo de la petición — que a menudo contiene contraseñas, tokens o PII — en un archivo de log que termina en un sistema centralizado con controles de acceso más débiles que la base de datos. Trata los logs como un almacén de datos con su propio modelo de amenazas. Si no pondrías un campo en una respuesta de API pública, no lo pongas en una línea de log que termina en Elasticsearch.
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)
- Nunca loggees contraseñas, tokens ni cuerpos completos de peticiones
- Incluye un ID de correlación en cada petición para trazabilidad
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 Producción
Lo que sigue es una checklist completa de producción para una API REST Node.js que sirve a 100K usuarios. Agrupé los 47 controles por categoría para que puedas tacklearlos en orden de riesgo. Cada fila linkea de vuelta a la sección que explica el porqué.
Autenticación y tokens de acceso. Esta es tu puerta principal. Si algo aquí falla, un atacante puede impersonar a cualquier usuario. JWT con RS256 importa porque HS256 te fuerza a compartir el secreto de firma con cada verificador — una vez que un segundo servicio necesita validar tokens, le diste las llaves al castillo.
| Control | Sección |
|---|---|
| JWT con RS256 (no HS256) | 1. Autenticación |
| Expiración de token: 15 min access, 7 días refresh | 1. Autenticación |
| Refresh token rotation | 1. Autenticación |
| MFA para endpoints admin | 1. Autenticación |
| Rate limiting en login: 5 intentos, luego lock 15 min | 4. Rate Limiting |
| No exponer token en URL | 1. Autenticación |
| Logout invalida token (Redis denylist) | 1. Autenticación |
| Password policy: min 12 chars, complejidad | 5. Encriptación |
Autorización e IDOR. La autorización de objetos rota es el riesgo #1 de API en el OWASP Top 10. Cada fila aquí existe porque alguien, en algún lado, publicó un endpoint que confiaba en el parámetro de la URL sin verificar ownership.
| Control | Sección |
|---|---|
| RBAC: roles user / admin / super_admin | 2. Autorización |
| Verificar ownership en cada petición (anti-IDOR) | 2. Autorización |
| Scope por recurso: user solo accede sus datos | 2. Autorización |
| Denegar por defecto, permitir explícitamente | 2. Autorización |
| No auto-increment IDs (usar UUID) | 2. Autorización |
Validación de entrada. El objetivo es simple: nunca confíes en lo que el cliente envía. Schema validation en cada endpoint atrapa mass assignment e inyección antes de que lleguen a tu base de datos. Un límite de 1 MB de payload evita que atacantes tiren tu server con un JSON de 500 MB.
| Control | Sección |
|---|---|
| Schema validation (Zod) en cada endpoint | 3. Validación de Entrada |
| Límite de tamaño de payload (max 1 MB) | 3. Validación de Entrada |
| Sanitización de strings (no HTML injection) | 3. Validación de Entrada |
| Queries parametrizadas (anti-SQL injection) | 3. Validación de Entrada |
| No eval/exec con input de usuario | 3. Validación de Entrada |
| File upload: validar tipo, tamaño, contenido | 3. Validación de Entrada |
Output y manejo de errores. Lo que tu API devuelve es tan importante como lo que acepta. Los stack traces filtran rutas de archivos y versiones de librerías. Un DTO mapping faltante puede exponer campos internos como is_admin o created_by.
| Control | Sección |
|---|---|
| No exponer stack traces en producción | 6. Manejo de Errores |
| DTO mapping: no exponer campos internos | 6. Manejo de Errores |
| Headers: X-Content-Type-Options, X-Frame-Options, CSP, HSTS | 8. CORS y Headers |
| No exponer versión del server/framework | 8. CORS y Headers |
| Rate limiting global: 100 req/min por usuario | 4. Rate Limiting |
Encriptación de transporte. TLS 1.3 es innegociable. HSTS con max-age de un año le dice a los navegadores que siempre usen HTTPS, previniendo ataques SSL strip en Wi-Fi público. Certificate pinning importa para mobile apps donde el certificate store del SO es menos confiable.
| Control | Sección |
|---|---|
| TLS 1.3 obligatorio (no TLS 1.0/1.1) | 5. Encriptación |
| Redirect HTTP a HTTPS | 5. Encriptación |
| HSTS: max-age=31536000; includeSubDomains | 5. Encriptación |
| Certificate pinning (mobile apps) | 5. Encriptación |
Configuración y secretos. Una política CORS wildcard (Access-Control-Allow-Origin: *) deja que cualquier sitio web llame a tu API con las cookies del usuario. Secretos en .env funcionan para desarrollo, pero en producción necesitás un secrets manager con rotación.
| Control | Sección |
|---|---|
| CORS: origin estricto, no wildcard | 8. CORS y Headers |
| NODE_ENV=production | 9. Endurecimiento de Despliegue |
| Secrets en Secrets Manager (no .env en prod) | 5. Encriptación |
| Helmet() configurado | 8. CORS y Headers |
| Compression con Brotli (no gzip para evitar BREACH) | 5. Encriptación |
Logging y monitoreo. Sin audit logs ni alertas, te enteras de los breaches por tus usuarios — o por un periodista. La regla es: loggeá lo suficiente para reconstruir qué pasó, pero nunca loggees secretos, tokens ni PII.
| Control | Sección |
|---|---|
| Audit log de acciones críticas | 7. Logging y Monitoreo |
| No loggear secrets, passwords, tokens, PII | 7. Logging y Monitoreo |
| Alertas de intentos de auth fallidos | 7. Logging y Monitoreo |
| Alertas de rate limit excedido | 7. Logging y Monitoreo |
| SIEM integration (ELK + alerting) | 7. Logging y Monitoreo |
Dependencias y CI/CD. La última capa es tu supply chain. Un paquete npm vulnerable o una API key leakeada en git pueden deshacer todos los controles de arriba. Estos items hacen de la seguridad un gate de CI, no una revisión manual.
| Control | Sección |
|---|---|
| npm audit en CI (—audit-level=high) | 9. Endurecimiento de Despliegue |
| Dependabot o Snyk configurado | 9. Endurecimiento de Despliegue |
| Lockfile commiteado (package-lock.json) | 9. Endurecimiento de Despliegue |
| License check en CI | 9. Endurecimiento de Despliegue |
| SAST (semgrep) en pipeline | 9. Endurecimiento de Despliegue |
| DAST (OWASP ZAP) en staging | 9. Endurecimiento de Despliegue |
| Container scan (Trivy) en build | 9. Endurecimiento de Despliegue |
| Secret scan (git-secrets) en pre-commit | 9. Endurecimiento de Despliegue |
| Code review obligatorio (1 approver min) | 9. Endurecimiento de Despliegue |
Lecciones de correr esta checklist en producción:
- 47 items es el suelo para una API en producción, no el techo.
- IDOR es el riesgo #1: verifica ownership en cada petición, sin excepciones.
- Schema validation en cada endpoint atrapa mass assignment e inyección antes de que lleguen a tu base de datos.
- Audit logging más alertas te da detección temprana — sin eso, te enteras de los breaches por tus usuarios.
- SAST, DAST y secret scanning en CI son la única forma de prevenir regresiones a medida que el equipo crece.
Lo que Funciona
- Rota las claves de firma JWT cada 90 días con key versioning. Embebe el key ID en el header
kidpara que los verificadores puedan fetchear la clave pública correcta sin downtime durante la rotación. - Aplica límites de rate diferentes por clase de endpoint. Login y reseteo de contraseña: 5 req/min por IP. Endpoints de lectura: 100 req/min por usuario. Endpoints de escritura: 30 req/min por usuario. Un solo límite global o bloquea tráfico legítimo o deja pasar abuso.
- Devuelve 404, no 403, para recursos que el llamador no posee. Un 403 confirma que el recurso existe, lo que permite a los atacantes enumerar. Un 404 no les da nada.
- Trata los logs como un almacén de datos con su propio modelo de amenazas. Si un campo no debería estar en una respuesta de API pública, no debería estar en una línea de log que termina en Elasticsearch con controles de acceso más débiles.
- Conecta SAST y secret scanning en pre-commit, no solo en CI. Atrapar un secreto hardcodeado antes de que llegue al remoto es infinitamente más barato que rotarlo después de un push.
Preguntas frecuentes
¿Debería usar OAuth 2.0 o API keys para mi API?
OAuth 2.0 para APIs orientadas a usuarios con integraciones de terceros. API keys son adecuadas para server-to-server donde la clave se mantiene secreta.
¿Con qué frecuencia debo rotar las claves de firma?
Al menos anualmente, o inmediatamente si hay compromiso. Usa versionado de claves para rotar sin downtime.
¿Es GraphQL menos seguro que REST?
Ninguno es más seguro por naturaleza — simplemente fallan distinto. GraphQL le da al atacante un lenguaje de queries poderoso, así que necesitás límites de profundidad, scoring de complejidad y autorización a nivel de campo para que no pidan toda tu base de datos en una sola query. REST es más simple pero hereda los mismos problemas de IDOR y validación. Para las defensas específicas de GraphQL — control de introspección, límites de costo, persisted queries — consulta la Guía Completa de Seguridad en GraphQL.
¿Cómo empiezo con esto en un proyecto existente?
No intentes arreglar todo a la vez. Buscá el endpoint que maneja los datos más sensibles — usualmente auth o pagos — y aplicá las secciones 1-3 (autenticación, autorización, validación de entrada) a esa sola ruta. Publícalo, mirá los logs por una semana, y después pasá al siguiente endpoint. El hardening incremental le gana a un rewrite en grande que nunca sale a producción.
¿Qué herramientas necesito para ejecutar estos chequeos en CI?
Para Node.js: helmet para headers, zod para validación, express-rate-limit para throttling, semgrep para SAST, npm audit --audit-level=high para dependencias, y trivy para escaneo de contenedores. Para Python: pydantic para validación, flask-limiter para throttling, bandit para SAST, y pip-audit para dependencias.
¿Cómo mido el éxito después de implementar esto?
Rastrea tres métricas: intentos de autenticación fallidos por día (debería estabilizarse, no crecer), respuestas 429 de rate limit por día (picos indican abuso o un cliente mal configurado), y tiempo de detección para cualquier incidente de seguridad (objetivo: menos de 24 horas desde el log de auditoría hasta la alerta).
¿Cómo priorizo si tengo poco tiempo?
Empieza por autenticación (JWT seguro + rate limiting), autorización (verificar ownership), validación de entrada (Zod en cada endpoint) y TLS. Estos cuatro cubren aproximadamente el 80% de las vulnerabilidades. Después agrega headers de seguridad (helmet), logging de auditoría, y escaneo de dependencias. Finalmente, conecta SAST/DAST en CI. Trata la checklist como una revisión recurrente, no como una verificación única — re-córrala cada trimestre y tras cualquier cambio mayor de endpoints.
Recursos Relacionados
API Security
Asegurar tus APIs end-to-end. Cubre rate limiting, autenticacion, input validation, CORS, prevencion de SQL injection, API gateway patterns, limites de request size, pagination security, mass assignment, versioning, audit logging y API security testing con ejemplos de codigo.
GuideGuí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)
Un recorrido enfocado en desarrolladores por el OWASP Top 10 — inyección, XSS, control de acceso roto, SSRF y el resto — con código de prevención y un flujo de threat modeling.
GuideDiseño de API Gateway: Resiliencia, Enrutamiento y Seguridad
Guía práctica para diseñar API gateways: enrutamiento, autenticación, rate limiting, circuit breakers, caché y patrones de despliegue para APIs resilientes.
GuideSeguridad CI/CD: Fortalece tus Pipelines y Previene
Guía práctica para asegurar pipelines CI/CD: gestión de secretos, runners de mínimo privilegio, firma de artefactos, escaneo de dependencias y defensa contra ataques de supply chain.
DocPlantilla de Revisión de Seguridad de API (OWASP)
Una plantilla de checklist rellenable para revisar autenticación, autorización, rate limiting y cobertura del OWASP API Security Top 10.