🎉
¡Se viene el black friday!! Para quienes querais comprar el libro bien de precio, aquí teneis un descuentazo del 15%!!;
Pero aprovechalo, porque la semana que viene será menor descuento!

CORS en profundidad: orígenes, preflight y cabeceras explicados

🏠 Web API 📅 23 Nov 2025 ⏱️ 10 min 💬 0

Como desarrolladores la gran mayoría hemos sufrido problemas con CORS o la comunicación y entre componentes, en este post, voy a explicar que es CORS, cómo funciona y por qué es necesario tener CORS configurado de una forma correcta

 

 

 

1 - ¿Qué es CORS? 

 

CORS es un acrónimo que viene de Cross-Origin Resource Sharing, y es un mecanismo de seguridad para el navegador que permite a un servidor indicar de qué orígenes permitimos cargar recursos.

Estos orígenes incluyen el dominio, protocolo y puerto.

 

Lo que significa que si tenemos una API expuesta al exterior, podemos configurarla para que el contenido de esta API pueda ser cargado desde una página web nuestra pero no desde una web de terceros.

cors explanation

Esta configuración se define en el lado de la API y afecta incluso a los subdominios, para que la configuración de la imagen funcione, debemos definir del lado de la api que ese dominio es capaz de realizar llamadas HTTP. 

Aún así, esto es un mecanismo de seguridad del navegador, por lo que si estás realizando llamadas a una API desde fuera de un navegador, estas no se verán afectadas por CORS. 

Este tipo de llamadas incluyen softwares como Postman, insomnia o si haces la llamada HTTP desde un lenguaje de programación.

 

En caso de que desarrolles una API y esta no tenga CORS configurado, el navegador verificará la política “same origin” donde tanto el sitio que hace la llamada como el que la recibe deben de ser el mismo. 

 

NOTA: CORS verifica el header origin, así que si se lo añades a la llamada de forma manual, si lo hace.

 

 

2 - ¿Por qué necesitamos CORS?

 

CORS es necesario porque el navegador no confía de forma implícita en que los sitios que visita realicen solicitudes a otros sitios. Esta política no está para proteger a quien realiza la llamada, sino para proteger al servidor que las recibe. Por eso es el servidor de destino quien decide qué orígenes están permitidos.

 

Sin las restricciones, un script sencillo que cargue repetidamente una página podría distribuirse mediante inyección de código, y cualquier navegador que ejecute este script podría contribuir a un ataque de denegación de servicio (DDoS). Gracias a CORS (y a la política de same origin), el navegador limita el impacto de dicho script.

 

Otra protección clave que ofrece CORS es contra la falsificación de peticiones entre sitios (CSRF). Evita que un sitio realice ciertos tipos de solicitudes a otro sitio empleando los tokens existentes como las cookies de sesión.

 

 

3 - CORS Preflight

 

Si has trabajado con sistemas donde el front end está separado del Back End es posible que te hayas dado cuenta de que algunas llamadas desde el front en se duplican, o eso parece. 

 

En verdad estas llamadas no se están duplicando, lo que estamos haciendo es generar una llamada preflight.

 

Esta llamada es una request adicional que lanza el navegador de forma automática para ciertas peticiones, por ejemplo, con peticiones PUT, DELETE, el navegador enviará primero una petición OPTIONS para preguntarle al servidor si permite la operación.

cors prefligt explicado

En caso de que la respuesta del servidor no sea satisfactoria, el navegador no lanzará la petición real.  

 

3.1 - Reglas para lanzar una petición Preflight

 

No todas las peticiones lanzan un preflight, de hecho podemos definir las peticiones que realizamos en dos tipos, peticiones simples y peticiones que no son simples.

 

Las peticiones simples son las que no mandan un Preflight y reúnen las siguientes características: 

  1. Si el método de la request es Get, Head o POST.
  2. La request no tiene headers personalizados y usa los siguientes: accept, accept-language, Content-language, Content-type* y Range.

Para el caso de Content-type hay un caso especial para POST, y es que entran en la categoría de simple si son application/x-www-form-urlencoded, multipart/form-data o text/plain. Cualquier otro content-type lanza preflight. 

 

Las peticiones que no se consideran simples son las que no cumplen con esas reglas.

  1. Si la petición es PUT, DELETE o cualquier otro método.
  2. Usas cabeceras propias como Authorization, token, etc.
  3. En el caso de post, si el content-type no cuadra con los aceptados. 

 

En el caso de que se lanze la Preflight el servidor responderá con los encabezados correctos como podemos ver en el ejemplo y un código de estado satisfactorio (200/204): 

preflight headers

  • Access-Control-Allow-Origin: Indica los orígenes que pueden realizar llamadas, puede ser * para todos.
  • Access-Control-Allow-Methods: Métodos HTTP disponibles.
  • Access-Control-Allow-Headers: devuelve si los métodos que se envían en la petición preflight son válidos.
  • Access-Control-Allow-Credentials: verdadero en caso de permitir cookies o Authorization headers.
  • Access-Control-Max-Age: Indica al navegador durante cuánto tiempo se puede saltar los Preflights. 

 

 

4 - CORS en .NET

 

Dentro de .NET, o C# en particular, configurar CORS es super sencillo. Si tenemos un proyecto api lo único que debemos hacer es utilizar el método extensible correspondiente, ya que nos viene con el framework:

 

builder.Services.AddCors();

 

Pero aquí no estamos especificando ninguna opción, por lo que no hace nada, así que solo permitirá llamadas del mismo origen. 

 

Lo que debemos hacer es definir los orígenes de donde queremos poder responder. 

Para ello definimos una política, en esta política le indicamos de qué orígenes, en qué métodos y que cabeceras de los mensajes. 

 

builder.Services.AddCors(options =>
{
    options.AddDefaultPolicy(policy => policy
        .AllowAnyOrigin()
        .AllowAnyHeader()
        .AllowAnyMethod());
});

En muchos casos dejamos cualquier método y cualquier cabecera ya que suelen ser servicios propios de los que nos fiamos, pero si quieres ser más restrictivo siempre puedes indicar qué métodos HTTP y que cabeceras quieres poder permitir. 

Si quieres ser más restrictivo aún, puedes tener múltiples políticas que luego puedes especificar en los propios endpoints. 

builder.Services.AddCors(options =>
{
    options.AddPolicy("publicsite", policy => policy
        .WithOrigins("https://www.web.com")
        .AllowAnyHeader()
        .WithMethods("GET"));

    options.AddPolicy("adminsite", policy => policy
        .WithOrigins("https://admin.web.com")
        .WithHeaders("Content-Type", "Authorization")
        .AllowAnyMethod()
        .AllowCredentials());
});

 

Posteriormente debemos utilizar Cors dentro de nuestro WebApplication para tener una política de cors global 

app.UseCors();

 

O como hemos mencionado, se puede aplicar por endpoint:

app.MapPost("/admin", () =>
{
//Logic here
}).RequireCors("adminsite");

 

Con respecto a las llamadas preflight, en ASP.NET no tenemos que tocar nada, ya que si un endpoint existe al utilizar `UseCors` las llamadas preflight funcionan automáticamente. Aún así, si quisieras, puedes interceptar dichas llamadas en un middleware


💬 Comentarios