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:4300
en 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 XMLHttpRequest
y 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.
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-Origin
a 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
, POST
o lo que sea que estaba tratando de enviar) y responder a ella con el derecho Access-Control-Allow-Origin
header sino también Access-Control-Allow-Methods
y Access-Control-Allow-Headers
para 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-Origin
y 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/json
encabezado en una solicitud GET que no tiene un cuerpo de solicitud para describir el contenido (generalmente cuando el autor confunde Content-Type
y 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 fetch
API (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 fetch
y 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-Origin
encabezado ' ' 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).