XMLHttpRequest no puede cargar XXX No hay encabezado 'Access-Control-Allow-Origin'

111

tl; dr; Acerca de la política del mismo origen

Tengo un proceso Grunt que inicia una instancia del servidor express.js. Esto funcionó absolutamente bien hasta ahora, cuando comenzó a mostrar una página en blanco con lo siguiente que aparece en el registro de errores en la consola del desarrollador en Chrome (última versión):

XMLHttpRequest no puede cargar https://www.example.com/ No hay un encabezado 'Access-Control-Allow-Origin' presente en el recurso solicitado. Por lo tanto, no se permite el acceso al origen ' http: // localhost: 4300 '.

¿Qué me impide acceder a la página?

Peter David Carter
fuente
Estoy trabajando en el sitio web y estuvo bien hace cinco minutos.
Peter David Carter
1
¿Emite encabezados CORS? quizás si compartiera algún código sería más fácil de ver
Jaromanda X
Plausiblemente. ¿A qué departamento debo preguntar para averiguarlo? Solo hago las cosas de backbone.marionette principalmente ...
Peter David Carter
Si. Supongo que las organizaciones de departamentos no siempre son uniformes de todos modos, por lo que posiblemente sea una pregunta nebulosa, pero me gustaría saber un poco de las cosas de backend / enrutamiento / administración de sistemas en mi empresa y esto me pareció una buena excusa para familiarizarme yo mismo, así que si hay problemas en el futuro, puedo ayudar.
Peter David Carter
Le preguntaría a alguien del lado del servidor dentro de su operación. Deben haberte cambiado si pudiste acceder a él antes.
Larry Lane

Respuestas:

205

tl; dr: hay un resumen al final y títulos en la respuesta para que sea más fácil encontrar las partes relevantes. Sin embargo, se recomienda leer todo, ya que proporciona antecedentes útiles para comprender el por qué, lo que facilita ver cómo se aplica el cómo en diferentes circunstancias.

Acerca de la política del mismo origen

Esta es la Política de Mismo Origen . Es una característica de seguridad implementada por navegadores.

Su caso particular muestra cómo se implementa para XMLHttpRequest (y obtendrá resultados idénticos si usara fetch), pero también se aplica a otras cosas (como imágenes cargadas en un <canvas>o documentos cargados en un <iframe>), solo con implementaciones ligeramente diferentes.

(Curiosamente, también se aplica a las fuentes CSS, pero eso se debe a que las fundiciones encontradas insistieron en DRM y no por los problemas de seguridad que generalmente cubre la Política del Mismo Origen).

El escenario estándar que demuestra la necesidad del POE se puede demostrar con tres caracteres :

  • Alice es una persona con un navegador web.
  • Bob tiene un sitio web ( https://www.[website].com/en tu ejemplo)
  • Mallory tiene un sitio web ( http://localhost:4300en su ejemplo)

Alice ha iniciado sesión en el sitio de Bob y tiene algunos datos confidenciales allí. Tal vez sea una intranet de la empresa (accesible solo para navegadores en la LAN), o su banca en línea (accesible solo con una cookie que obtiene después de ingresar un nombre de usuario y contraseña).

Alice visita el sitio web de Mallory, que tiene algo de JavaScript que hace que el navegador de Alice realice una solicitud HTTP al sitio web de Bob (desde su dirección IP con sus cookies, etc.). Esto podría ser tan simple como usar XMLHttpRequesty leer responseText.

La Política del mismo origen del navegador evita que JavaScript lea los datos devueltos por el sitio web de Bob (al que Bob y Alice no quieren que Mallory acceda). (Tenga en cuenta que puede, por ejemplo, mostrar una imagen usando un <img>elemento través orígenes debido a que el contenido de la imagen no está expuesto a JavaScript (o Mallory) ... a menos que tirar de la lona en la mezcla, en cuyo caso se va a generar un mismo origen error de infracción).


Por qué se aplica la política del mismo origen cuando no cree que debería

Para cualquier URL dada, es posible que el SOP no sea necesario. Un par de escenarios comunes donde este es el caso son:

  • Alice, Bob y Mallory son la misma persona.
  • Bob proporciona información completamente pública

… Pero el navegador no tiene forma de saber si alguno de los anteriores es cierto, por lo que la confianza no es automática y se aplica el SOP. El permiso debe otorgarse explícitamente antes de que el navegador proporcione los datos que se le dieron a un sitio web diferente.


Por qué la Política del mismo origen solo se aplica a JavaScript en una página web

Las extensiones del navegador *, la pestaña Red en las herramientas de desarrollo del navegador y aplicaciones como Postman son software instalado. No pasan datos de un sitio web al JavaScript que pertenece a un sitio web diferente solo porque usted visitó ese sitio web diferente . La instalación de software suele requerir una elección más consciente.

No hay un tercero (Mallory) que se considere un riesgo.

*Las extensiones del navegador deben escribirse con cuidado para evitar problemas de origen cruzado. Consulte la documentación de Chrome, por ejemplo .


Por qué puede mostrar datos en la página sin leerlos con JS

Hay una serie de circunstancias en las que el sitio de Mallory puede hacer que un navegador obtenga datos de un tercero y los muestre (por ejemplo, agregando un <img>elemento para mostrar una imagen). Sin embargo, no es posible que el JavaScript de Mallory lea los datos en ese recurso, solo el navegador de Alice y el servidor de Bob pueden hacerlo, por lo que aún es seguro.


CORS

El encabezado de respuestaAccess-Control-Allow-Origin HTTP al que se hace referencia en el mensaje de error es parte del estándar CORS que le permite a Bob otorgar explícitamente permiso al sitio de Mallory para acceder a los datos a través del navegador de Alice.

Una implementación básica solo incluiría:

Access-Control-Allow-Origin: *

… En los encabezados de respuesta para permitir que cualquier sitio web lea los datos.

Access-Control-Allow-Origin: http://example.com/

... permitiría que solo un sitio específico acceda a él, y Bob puede generarlo dinámicamente en función del encabezado de la Origin solicitud para permitir que varios sitios, pero no todos, accedan a él.

Los detalles de cómo Bob establece ese encabezado de respuesta dependen del servidor HTTP de Bob y / o del lenguaje de programación del lado del servidor. Hay una colección de guías para varias configuraciones comunes que pueden ayudar.

Modelo de dónde se aplican las reglas CORS

NB: Algunas solicitudes son complejas y envían una solicitud de OPCIONES de verificación previa a la que el servidor tendrá que responder antes de que el navegador envíe GET / POST / PUT / Cualquier solicitud que JS quiera hacer. Las implementaciones de CORS que solo se agregan Access-Control-Allow-Origina URL específicas a menudo se tropiezan con esto.


Obviamente, otorgar permiso a través de CORS es algo que Bob solo haría solo si:

  • Los datos no eran privados ni
  • Mallory era de confianza

¡Pero no soy Bob!

No existe un mecanismo estándar para que Mallory agregue este encabezado porque tiene que provenir del sitio web de Bob, que ella no controla.

Si Bob está ejecutando una API pública, entonces puede haber un mecanismo para activar CORS (tal vez formateando la solicitud de cierta manera, o una opción de configuración después de iniciar sesión en un sitio del Portal de desarrolladores para el sitio de Bob). Sin embargo, este tendrá que ser un mecanismo implementado por Bob. Mallory podría leer la documentación en el sitio de Bob para ver si hay algo disponible, o podría hablar con Bob y pedirle que implemente CORS.


Mensajes de error que mencionan "Respuesta para verificación previa"

Algunas solicitudes de origen cruzado tienen verificación previa .

Esto sucede cuando (en términos generales) intenta realizar una solicitud de origen cruzado que:

  • Incluye credenciales como cookies
  • No se pudo generar con un formulario HTML normal (por ejemplo, tiene encabezados personalizados o un tipo de contenido que no se puede usar en un formulario enctype).

Si está haciendo correctamente algo que necesita una verificación previa

En estos casos, el resto de esta respuesta aún se aplica, pero también debe asegurarse de que el servidor pueda escuchar la solicitud de verificación previa (que será OPTIONS(y no GET, POSTo lo que sea que estaba tratando de enviar) y responder a ella con el derecho Access-Control-Allow-Originheader sino también Access-Control-Allow-Methodsy Access-Control-Allow-Headerspara permitir sus métodos o encabezados HTTP específicos.

Si está activando una verificación previa por error

A veces, las personas cometen errores al intentar construir solicitudes Ajax y, a veces, estos provocan la necesidad de una verificación previa. Si la API está diseñada para permitir solicitudes de origen cruzado, pero no requiere nada que necesite una verificación previa, esto puede interrumpir el acceso.

Los errores comunes que desencadenan esto incluyen:

  • tratando de poner Access-Control-Allow-Originy otros encabezados de respuesta CORS en la solicitud. Estos no pertenecen a la solicitud, no hacen nada útil (¿cuál sería el punto de un sistema de permisos en el que podría otorgarse permiso a sí mismo?), Y deben aparecer solo en la respuesta.
  • tratando de poner un Content-Type: application/jsonencabezado en una solicitud GET que no tiene un cuerpo de solicitud para describir el contenido (generalmente cuando el autor confunde Content-Typey Accept).

En cualquiera de estos casos, eliminar el encabezado de solicitud adicional a menudo será suficiente para evitar la necesidad de una verificación previa (que resolverá el problema al comunicarse con API que admiten solicitudes simples pero no solicitudes de verificación previa).


Respuestas opacas

A veces es necesario realizar una solicitud HTTP, pero no es necesario leer la respuesta. por ejemplo, si está publicando un mensaje de registro en el servidor para su grabación.

Si está utilizando la fetchAPI (en lugar de XMLHttpRequest), puede configurarla para que no intente utilizar CORS.

Tenga en cuenta que esto no le permitirá hacer nada que necesite que haga CORS. No podrá leer la respuesta. No podrá realizar una solicitud que requiera una verificación previa.

Le permitirá hacer una solicitud simple, no ver la respuesta y no llenar la Consola del desarrollador con mensajes de error.

Cómo hacerlo se explica por el mensaje de error de Chrome que aparece cuando realiza una solicitud utilizando fetchy no obtiene permiso para ver la respuesta con CORS:

La política CORS ha bloqueado el acceso a la búsqueda en ' https://example.com/' desde el origen ' https://example.net': No hay un Access-Control-Allow-Originencabezado ' ' presente en el recurso solicitado. Si una respuesta opaca satisface sus necesidades, configure el modo de la solicitud en 'no-cors' para obtener el recurso con CORS deshabilitado.

Así:

fetch("http://example.com", { mode: "no-cors" });

Alternativas a CORS

JSONP

Bob también podría proporcionar los datos utilizando un truco como JSONP, que es la forma en que las personas cruzaban el origen Ajax antes de que apareciera CORS.

Funciona presentando los datos en forma de un programa JavaScript que inyecta los datos en la página de Mallory.

Requiere que Mallory confíe en Bob para no proporcionar código malicioso.

Tenga en cuenta el tema común: el sitio que proporciona los datos debe decirle al navegador que está bien que un sitio de terceros acceda a los datos que está enviando al navegador.

Dado que JSONP funciona agregando un <script>elemento para cargar los datos en forma de un programa JavaScript que llama a una función que ya está en la página, intentar usar la técnica JSONP en una URL que devuelve JSON fallará, generalmente con un error CORB, porque JSON no es JavaScript.

Mueva los dos recursos a un solo origen

Si el documento HTML en el que se ejecuta JS y la URL que se solicita están en el mismo origen (compartiendo el mismo esquema, nombre de host y puerto), la Política del mismo origen otorga permiso de forma predeterminada. CORS no es necesario.

Un proxy

Mallory podría usar el código del lado del servidor para obtener los datos (que luego podría pasar de su servidor al navegador de Alice a través de HTTP como de costumbre).

O bien:

  • agregar encabezados CORS
  • convertir la respuesta a JSONP
  • existen en el mismo origen que el documento HTML

Ese código del lado del servidor podría ser escrito y alojado por un tercero (como CORS Anywhere). Tenga en cuenta las implicaciones de privacidad de esto: el tercero puede monitorear quién es proxy qué en sus servidores.

Bob no necesitaría otorgar ningún permiso para que eso suceda.

No hay implicaciones de seguridad aquí, ya que eso es solo entre Mallory y Bob. Bob no puede pensar que Mallory es Alice y proporcionar a Mallory datos que deben mantenerse confidenciales entre Alice y Bob.

En consecuencia, Mallory solo puede utilizar esta técnica para leer datos públicos .

Sin embargo, tenga en cuenta que tomar contenido del sitio web de otra persona y mostrarlo por su cuenta podría ser una violación de los derechos de autor y exponerlo a acciones legales.

Escribir algo que no sea una aplicación web

Como se indica en la sección "Por qué la Política del mismo origen solo se aplica a JavaScript en una página web", puede evitar el SOP si no escribe JavaScript en una página web.

Eso no significa que no pueda continuar usando JavaScript y HTML, pero podría distribuirlo usando algún otro mecanismo, como Node-WebKit o PhoneGap.

Extensiones de navegador

Es posible que una extensión del navegador inyecte los encabezados CORS en la respuesta antes de que se aplique la Política del mismo origen.

Estos pueden ser útiles para el desarrollo, pero no son prácticos para un sitio de producción (pedir a cada usuario de su sitio que instale una extensión de navegador que deshabilite una función de seguridad de su navegador no es razonable).

También tienden a funcionar solo con solicitudes simples (fallan al manejar solicitudes de OPCIONES de verificación previa).

Tener un entorno de desarrollo adecuado con un servidor de desarrollo local suele ser un mejor enfoque.


Otros riesgos de seguridad

Tenga en cuenta que SOP / CORS no mitigan los ataques de inyección de XSS , CSRF o SQL que deben manejarse de forma independiente.


Resumen

  • No hay nada que pueda hacer en su código del lado del cliente que permita el acceso de CORS al servidor de otra persona .
  • Si controla el servidor, la solicitud se realiza para: Agregar permisos CORS.
  • Si eres amigable con la persona que lo controla: Haz que le agreguen permisos CORS.
  • Si es un servicio público:
    • Lea la documentación de su API para ver qué dicen sobre cómo acceder a ella con JavaScript del lado del cliente:
      • Es posible que le indiquen que use URL específicas
      • Pueden admitir JSONP
      • Es posible que no admitan el acceso de origen cruzado desde el código del lado del cliente (esto podría ser una decisión deliberada por motivos de seguridad, especialmente si tiene que pasar una clave API personalizada en cada solicitud).
    • Asegúrese de no activar una solicitud de verificación previa que no necesita. La API puede otorgar permiso para solicitudes simples, pero no para solicitudes de verificación previa.
  • Si no se aplica nada de lo anterior: haga que el navegador se comunique con su servidor, y luego haga que su servidor obtenga los datos del otro servidor y los transmita. (También hay servicios alojados de terceros que adjuntan encabezados CORS a recursos de acceso público que puede usar).
Quentin
fuente
Si ejecuto una LAN local en un servidor web e intento hacer una carga ajax desde la IP / URL, ¿funcionará? Todavía no lo he probado. ya que mi servidor web recuperando los datos json sería un MCU
Ciasto piekarz
@Ciastopiekarz - Se aplican las reglas normales del mismo origen / diferente origen. Se aplican las reglas de enrutamiento de red normales.
Quentin
25
La respuesta más completa que he leído, en lugar de solo un enlace sobre cors ..
pungggi
@Quentin - ¡Guau! +1! Entonces, lo que debo entender es que si Alice usa la extensión CORS, el servidor piensa que sus llamadas http no son de javascript sino de una extensión del navegador y las trata como una solicitud normal del mismo origen.
snippetkid
@snippetkid - No. En el caso habitual, el servidor enviará encabezados CORS en cada respuesta y no le importa de dónde vino la solicitud. Es responsabilidad del navegador permitir o denegar el acceso a los datos al JS según los encabezados CORS en la respuesta. (Las cosas se ponen un poco más complejas en el servidor cuando se trata de solicitudes de verificación previa)
Quentin
3

El servidor de destino debe permitir la solicitud de origen cruzado. Para permitirlo a través de Express, simplemente maneje la solicitud de opciones http:

app.options('/url...', function(req, res, next){
   res.header('Access-Control-Allow-Origin', "*");
   res.header('Access-Control-Allow-Methods', 'POST');
   res.header("Access-Control-Allow-Headers", "accept, content-type");
   res.header("Access-Control-Max-Age", "1728000");
   return res.sendStatus(200);
});
Daphoque
fuente
3

Como esto no se menciona en la respuesta aceptada.

  • Este no es el caso de esta pregunta exacta, pero podría ayudar a otras personas que buscan ese problema.
  • Esto es algo que puede hacer en su código de cliente para evitar errores CORS en algunos casos .

Puede hacer uso de Solicitudes simples .
Para realizar una 'Solicitud simple', la solicitud debe cumplir varias condiciones. Por ejemplo, sólo permite POST, GETy HEADmétodo, así como permitiendo sólo algunas cabeceras dado (usted puede encontrar todas las condiciones aquí ).

Si el código de su cliente no establece explícitamente los encabezados afectados (por ejemplo, "Aceptar") con un valor fijo en la solicitud, es posible que algunos clientes establezcan estos encabezados automáticamente con algunos valores "no estándar", lo que hace que el servidor no los acepte como Solicitud simple - que le dará un error CORS.

zwif
fuente
2

Esto sucede debido al error CORS. CORS son las siglas de Cross Origin Resource Sharing. En pocas palabras, este error se produce cuando intentamos acceder a un dominio / recurso desde otro dominio.

Lea más sobre esto aquí: error CORS con jquery

Para solucionar esto, si tiene acceso al otro dominio, tendrá que permitir Access-Control-Allow-Origin en el servidor. Esto se puede agregar en los encabezados. Puede habilitar esto para todas las solicitudes / dominios o un dominio específico.

Cómo hacer que funcione una solicitud de publicación de recursos compartidos de origen cruzado (CORS)

Estos enlaces pueden ayudar

Vishnu
fuente
0

Este problema de CORS no se desarrolló más (por otras causas).

Actualmente tengo este problema por diferentes motivos. Mi interfaz también está devolviendo el error de encabezado 'Access-Control-Allow-Origin'.

Solo que señalé la URL incorrecta, por lo que este encabezado no se reflejó correctamente (en lo que supongo que sí). localhost (front-end) -> llamar a http no seguro (se supone que es https), asegúrese de que el punto final de la API desde el front-end apunte al protocolo correcto.

morph85
fuente
0

Recibí el mismo error en la consola de Chrome.

Mi problema era que intentaba ir al sitio usando en http://lugar de https://. Así que no había nada que arreglar, solo tenía que ir al mismo sitio usando https.

Subhashi
fuente
-1

La solicitud "Obtener" con la adición de encabezados se transforma en la solicitud "Opciones". Entonces ocurren problemas de política de Cors. Tienes que implementar la solicitud de "Opciones" en tu servidor.

kira
fuente
-6

Debe habilitar CORS para que funcione.

Perostek Balveda
fuente