Aplicar Medidas de Seguridad: CORS, Rate Limiting y Validación

Video
15 min~5 min lectura

Reproductor de video

Concepto clave

En el desarrollo de APIs modernas, la seguridad no es un lujo sino una necesidad fundamental. CORS (Cross-Origin Resource Sharing), Rate Limiting y Validación forman una trinidad defensiva que protege tu API desde diferentes ángulos. Imagina tu API como un edificio de oficinas: CORS es el sistema de control de acceso que decide quién puede entrar desde qué puertas, Rate Limiting es el guardia que evita que demasiadas personas entren al mismo tiempo causando caos, y la Validación es el detector de metales que revisa que nadie lleve objetos peligrosos.

CORS especifica qué dominios externos pueden consumir tu API, previniendo ataques de CSRF y protegiendo datos sensibles. Rate Limiting controla la cantidad de solicitudes que un cliente puede hacer en un período determinado, protegiendo contra ataques de denegación de servicio (DDoS) y abuso de recursos. La Validación asegura que los datos entrantes cumplan con las reglas de negocio antes de procesarlos, evitando inyecciones y corrupción de datos.

Cómo funciona en la práctica

Implementar estas medidas en FastAPI sigue un patrón claro. Primero, configuras CORS usando fastapi.middleware.cors para definir orígenes permitidos, métodos HTTP y headers. Luego, integras Rate Limiting con bibliotecas como slowapi o fastapi-limiter para establecer límites por IP, usuario o endpoint. Finalmente, aplicas Validación exhaustiva usando los modelos Pydantic de FastAPI, combinando validadores nativos con custom validators.

Veamos el flujo completo: cuando una solicitud llega a tu API, primero pasa por el middleware CORS que verifica si el origen está permitido. Si pasa, el middleware de Rate Limiting revisa si el cliente no ha excedido sus cuotas. Solo entonces la solicitud llega al endpoint, donde Pydantic valida automáticamente los datos según tus modelos. Este enfoque por capas crea defensas profundas.

Código en acción

Configuración completa de seguridad en FastAPI:

from fastapi import FastAPI, Depends, HTTPException, status
from fastapi.middleware.cors import CORSMiddleware
from pydantic import BaseModel, Field, validator
from typing import Optional
import time

# Configuración CORS
app = FastAPI(title="API Segura")

app.add_middleware(
    CORSMiddleware,
    allow_origins=["https://mi-frontend.com", "http://localhost:3000"],
    allow_credentials=True,
    allow_methods=["GET", "POST", "PUT", "DELETE"],
    allow_headers=["Authorization", "Content-Type"],
)

# Implementación básica de Rate Limiting
from collections import defaultdict
from datetime import datetime, timedelta

request_log = defaultdict(list)
RATE_LIMIT = 100  # solicitudes por hora
TIME_WINDOW = 3600  # segundos

def rate_limit_middleware(client_ip: str):
    now = datetime.now()
    window_start = now - timedelta(seconds=TIME_WINDOW)
    
    # Filtrar solicitudes dentro de la ventana
    recent_requests = [req_time for req_time in request_log[client_ip] 
                      if req_time > window_start]
    
    if len(recent_requests) >= RATE_LIMIT:
        raise HTTPException(
            status_code=status.HTTP_429_TOO_MANY_REQUESTS,
            detail="Límite de tasa excedido"
        )
    
    request_log[client_ip].append(now)
    # Limpiar registros antiguos
    request_log[client_ip] = [req for req in request_log[client_ip] 
                             if req > window_start]

# Modelo con validación avanzada
class UserCreate(BaseModel):
    email: str = Field(..., min_length=5, max_length=100)
    password: str = Field(..., min_length=8, max_length=100)
    age: Optional[int] = Field(None, ge=18, le=120)
    
    @validator('email')
    def validate_email(cls, v):
        if '@' not in v:
            raise ValueError('Email inválido')
        return v.lower()
    
    @validator('password')
    def validate_password(cls, v):
        if not any(c.isupper() for c in v):
            raise ValueError('La contraseña debe contener al menos una mayúscula')
        if not any(c.isdigit() for c in v):
            raise ValueError('La contraseña debe contener al menos un número')
        return v

@app.post("/users/")
async def create_user(user: UserCreate, client_ip: str = Depends(lambda: "127.0.0.1")):
    # Aplicar rate limiting
    rate_limit_middleware(client_ip)
    
    # La validación ya ocurrió automáticamente gracias a Pydantic
    return {"message": "Usuario creado", "email": user.email}

Errores comunes

  • Configurar CORS demasiado permisivo: Usar allow_origins=["*"] en producción expone tu API a ataques. Siempre especifica dominios exactos.
  • Rate Limiting sin diferenciación de endpoints: Aplicar el mismo límite a todos los endpoints puede afectar la UX. Endpoints críticos como login necesitan límites más estrictos.
  • Validación incompleta: Confiar solo en validación del frontend. La validación debe ocurrir siempre en el backend, donde tienes control total.
  • No limpiar logs de Rate Limiting: Acumular registros indefinidamente consume memoria. Implementa limpieza periódica como se muestra en el ejemplo.
  • Ignorar headers de CORS: No configurar allow_headers correctamente puede bloquear solicitudes legítimas con headers personalizados.

Checklist de dominio

  1. ¿Configuraste CORS especificando dominios exactos en lugar de usar "*"?
  2. ¿Implementaste Rate Limiting con límites diferenciados por tipo de endpoint?
  3. ¿Validas todos los datos de entrada con Pydantic, incluyendo custom validators?
  4. ¿Probaste tu configuración CORS desde diferentes orígenes?
  5. ¿Monitorizas las solicitudes bloqueadas por Rate Limiting para ajustar límites?
  6. ¿Incluiste mensajes de error claros cuando falla la validación?
  7. ¿Documentaste tus políticas de seguridad para el equipo?

Implementar API segura con FastAPI

Construye una API REST completa que implemente las tres medidas de seguridad aprendidas. Sigue estos pasos:

  1. Crea un nuevo proyecto FastAPI con un endpoint /products/ que acepte POST para crear productos
  2. Configura CORS para permitir solo estos orígenes: https://tienda.com y http://localhost:8080
  3. Implementa Rate Limiting que permita máximo 50 solicitudes por hora por IP para el endpoint de productos
  4. Crea un modelo Pydantic para Producto con estas validaciones:
    • Nombre: entre 3 y 100 caracteres
    • Precio: mayor que 0 y menor que 1000000
    • Categoría: debe ser una de estas: "electronica", "ropa", "hogar"
    • Stock: entero no negativo
  5. Agrega un custom validator que verifique que productos de categoría "electronica" tengan precio mayor a 100
  6. Prueba tu implementación con diferentes casos: orígenes permitidos/no permitidos, exceso de solicitudes, datos inválidos
Pistas
  • Usa Enum de Python para las categorías válidas
  • Considera usar bibliotecas como slowapi para Rate Limiting más robusto
  • Prueba los headers CORS con herramientas como curl o Postman

Evalua tu comprension

Completa el quiz interactivo de arriba para ganar XP.