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.
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.
// 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.
// 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
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
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
}));
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;
}
}
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 activaAccess-Control-Allow-Credentials: true, la cabeceraAccess-Control-Allow-Originnunca 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
alwaysen Nginx: Si no se incluye la palabra clavealwaysal 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.