Todo desarrollador web ha tropezado alguna vez con el temido mensaje Access to fetch at '...' has been blocked by CORS policy en la consola del navegador. Esta experiencia, a menudo frustrante, marca el encuentro con uno de los mecanismos de seguridad más vitales y, a la vez, incomprendidos de la web moderna: CORS. Este artículo no solo te guiará para resolver estos errores, sino que te ayudará a comprender la lógica subyacente y la importancia de CORS en la arquitectura de seguridad de las aplicaciones web.

¿Qué es la Política del Mismo Origen (SOP)?

Los navegadores web implementan una piedra angular de la seguridad, conocida como la Política del Mismo Origen (SOP). Esta norma fundamental dicta que un documento o script cargado desde un origen puede interactuar únicamente con recursos del mismo origen. Para que dos URLs se consideren del 'mismo origen', deben compartir exactamente el mismo protocolo, nombre de host y puerto.

Comparación de Orígenes
https://example.com/page1  →  https://example.com/page2     ✅ Mismo origen
https://example.com        →  http://example.com             ❌ Protocolo diferente
https://example.com        →  https://api.example.com        ❌ Host diferente
https://example.com        →  https://example.com:8080       ❌ Puerto diferente

La SOP actúa como un escudo crucial, impidiendo que un script malintencionado en un sitio web acceda a datos sensibles de otro. Imagina las implicaciones: sin esta política, un sitio web fraudulento podría, por ejemplo, realizar solicitudes a la API de tu banco utilizando tus cookies de sesión, exponiendo tu información financiera. Por eso, la SOP es esencial para la privacidad y seguridad de los usuarios en la web.

¿Qué es CORS y por qué es necesario?

CORS (Cross-Origin Resource Sharing), o Compartición de Recursos entre Orígenes, es un mecanismo ingenioso diseñado para relajar de forma controlada las estrictas restricciones de la Política del Mismo Origen. Permite que un servidor web, de manera explícita y segura, autorice a ciertos orígenes externos a acceder a sus recursos. Esta comunicación vital se logra mediante un conjunto específico de cabeceras HTTP que el servidor incluye en sus respuestas.

Desentrañando el Funcionamiento de CORS

Solicitudes Simples: El Camino Directo

Cuando se trata de peticiones "simples" —típicamente solicitudes GET o POST que emplean un conjunto limitado de cabeceras HTTP seguras—, el navegador procede a enviar la petición directamente al servidor. Tras recibir la respuesta, el navegador examina las cabeceras HTTP en busca de la directiva Access-Control-Allow-Origin para determinar si el origen solicitante tiene permiso.

Ejemplo de Solicitud CORS Simple
// El navegador envía:
GET /api/data HTTP/1.1
Host: api.example.com
Origin: https://myapp.com

// El servidor responde:
HTTP/1.1 200 OK
Access-Control-Allow-Origin: https://myapp.com
Content-Type: application/json

{"data": "..."}

Solicitudes Preflight (OPTIONS): La Negociación Previa

En contraste con las simples, las solicitudes "no simples" —como aquellas que utilizan métodos HTTP más allá de GET y POST (PUT, DELETE), incluyen cabeceras personalizadas o envían datos con tipos de contenido específicos como application/json— requieren un paso adicional de seguridad. Antes de enviar la petición real, el navegador inicia una solicitud OPTIONS, conocida como "preflight" o "vuelo previo". Esta es una consulta preliminar al servidor para determinar si la acción propuesta está permitida.

Ejemplo de Solicitud Preflight
// 1. El navegador envía la preflight:
OPTIONS /api/users HTTP/1.1
Host: api.example.com
Origin: https://myapp.com
Access-Control-Request-Method: DELETE
Access-Control-Request-Headers: Content-Type, Authorization

// 2. El servidor responde con métodos/cabeceras permitidos:
HTTP/1.1 204 No Content
Access-Control-Allow-Origin: https://myapp.com
Access-Control-Allow-Methods: GET, POST, PUT, DELETE
Access-Control-Allow-Headers: Content-Type, Authorization
Access-Control-Max-Age: 86400

// 3. El navegador envía la solicitud real (solo si la preflight tiene éxito)

Cabeceras de Respuesta CORS Esenciales

Cabeceras CORS Clave
Access-Control-Allow-Origin: https://myapp.com   // Orígenes permitidos para acceder
Access-Control-Allow-Methods: GET, POST, PUT       // Métodos HTTP permitidos
Access-Control-Allow-Headers: Content-Type, Auth   // Cabeceras de solicitud permitidas
Access-Control-Allow-Credentials: true             // Permitir cookies/autenticación
Access-Control-Max-Age: 86400                      // Tiempo de caché para preflight (segundos)
Access-Control-Expose-Headers: X-Request-Id        // Cabeceras accesibles por JavaScript

Configuración de CORS en el Servidor

Express.js (Node.js)
import cors from 'cors';

app.use(cors({
  origin: ['https://myapp.com', 'https://staging.myapp.com'],
  methods: ['GET', 'POST', 'PUT', 'DELETE'],
  allowedHeaders: ['Content-Type', 'Authorization'],
  credentials: true,
  maxAge: 86400
}));
Nginx
location /api/ {
    add_header Access-Control-Allow-Origin "https://myapp.com" always;
    add_header Access-Control-Allow-Methods "GET, POST, PUT, DELETE" always;
    add_header Access-Control-Allow-Headers "Content-Type, Authorization" always;

    if ($request_method = OPTIONS) {
        return 204;
    }
}
PHP
header("Access-Control-Allow-Origin: https://myapp.com");
header("Access-Control-Allow-Methods: GET, POST, PUT, DELETE");
header("Access-Control-Allow-Headers: Content-Type, Authorization");

if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') {
    http_response_code(204);
    exit;
}

Errores Comunes y Trampas de CORS

  • El uso de Access-Control-Allow-Origin: * junto con credenciales: Esto es una receta para el bloqueo por parte del navegador. Cuando se activa Access-Control-Allow-Credentials: true, la cabecera Access-Control-Allow-Origin nunca puede ser *, sino que debe especificar un origen exacto (o una lista de ellos). Es un error frecuente que anula la seguridad deseada.
  • CORS es una característica de seguridad del navegador, NO del servidor: Es crucial entender que CORS protege a los *clientes web* (navegadores) de interacciones maliciosas con orígenes cruzados. No proporciona protección contra solicitudes directas de servidor a servidor. ¡Nunca confíes en CORS para la seguridad de tu API! La autenticación y autorización deben ser validadas en cada solicitud entrante en el backend, independientemente de la cabecera Origin.
  • Olvidar la directiva always en Nginx: Si no se incluye la palabra clave always al añadir las cabeceras CORS en Nginx, estas solo se enviarán si la solicitud se procesa con éxito (códigos 2xx). Esto significa que en caso de errores (4xx, 5xx), las cabeceras CORS no estarán presentes, lo que puede causar confusión y frustración durante la depuración, ya que el navegador seguirá bloqueando la respuesta.
  • No gestionar las solicitudes OPTIONS (preflight): Un error muy común es que el servidor no esté configurado para manejar explícitamente las solicitudes HTTP del método OPTIONS. Si tu servidor responde con un 404 Not Found o 405 Method Not Allowed a una petición OPTIONS, el navegador abortará inmediatamente la solicitud real. Asegúrate de que tu backend esté preparado para responder a estas solicitudes preflight con un código 204 No Content y las cabeceras CORS apropiadas.

Prueba Nuestras Herramientas Gratuitas para Desarrolladores

Codifica URLs, decodifica Base64 y formatea JSON al instante, simplificando tu flujo de trabajo.