Esta traducción está incompleta. Por favor, ayuda a traducir este artículo del inglés.
Un recurso hace una solicitud HTTP de origen cruzado cuando solicita otro recurso de un dominio distinto al que pertenece. Por ejemplo, una página HTML localizada en https://domain-a.com hace una solicitud <img> src
a https://domain-b.com/image.jpg. Actualmente muchas páginas en la web cargan recursos como hojas de estilos CSS, imágenes y scripts de dominios separados.
Por razones de seguridad, los exploradores restringen las solicitudes HTTP de origen cruzado iniciadas dentro de un script. Por ejemplo, XMLHttpRequest sigue la política de mismo-origen . Por lo que, una aplicación usando XMLHttpRequest solo puede hacer solicitudes HTTP a su propio dominio. Para mejorar las aplicaciones web, los desarrolladores pidieron a los proveedores de navegadores que permitieran a XMLHttpRequest realizar solicitudes de dominio cruzado.
El W3C Grupo de Trabajo de Aplicaciones Web recomienda el nuevo mecanismo de Intercambio de Recursos de Origen Cruzado (CORS, por sus siglas en inglés). CORS da controles de acceso a dominios cruzados para servidores web, lo que habilita la transferencia segura de datos en dominios cruzados. Exploradores modernos usan CORS en un contenedor API - como XMLHttpRequest - para mitigar los riesgos de solicitudes HTTP de origen cruzado.
Este artiíulo es dirigido a administradores web, desarrolladores de servidores y desarrolladores de interfaz. Exploradores modernos manejan los componentes sobre el intercambio de origen cruzado del lado del cliente. Incluyendo encabezados y políticas de ejecución. Pero, este nuevo estándar determina que los servidores tienen que manejar las nuevas solicitudes y las respuestas de los encabezados. Se recomienda, como lectura suplementaria, otro articulo para desarrolladores de servidor discutiendo intercambio de origen cruzado desde una perspectiva de servidor(con fragmentos de código PHP).
Este estándar de intercambio de origen cruzado es utilizado para habilitar solicitudes HTTP de sitios cruzados para:
- Invocaciones de
XMLHttpRequest
API en una manera de sitio cruzado, como se discutió arriba. - Fuentes Web (para usos de fuente en dominios cruzados
@font-face
dentro de CSS), para que los servidores puedan mostrar fuentes TrueType que solo puedan ser cargadas por sitios cruzados y usadas por sitios web que lo tengan permitido. - Texturas WebGL.
- Imágenes dibujadas en patrones usando drawImage.
Este artículo es una discusión general sobre Intercambio de Recursos de Origin Cruzado, e incluye una discusión de los encabezados HTTP como los implementados en Firefox 3.5.
Resumen
El estándar de Intercambio de Recursos de Origen Cruzado trabaja añadiendo nuevos encabezados HTTP que permiten a los servidores describir el conjunto de orígenes que tienen permiso de leer la información usando un explorador web. Adicionalmente, para métodos de solicitud HTTP que causan efectos secundarios en datos del usuario (ien particular, para otros métodos HTTP que GET
, o para la utilización de POST
con algunos tipos MIME), la especificación sugiere que los exploradores "verifiquen" la solicitud, solicitando métodos soportados desde el servidor con un método de solicitud HTTP OPTIONS
, y luego, con la "aprobación" del servidor, enviar la verdadera solicitud con el método de solicitud HTTP verdadero. Los servidores pueden también notificar a los clientes cuando sus "credenciales" (incluyendo Cookies y datos de autenticación HTTP) deben ser enviados con solicitudes.
Las secciones siguientes discuten escenarios, así como el análisis de los encabezados HTTP usados.
Ejemplos de escenarios de control de accesos
Aquí, presentamos tres escenarios que ilustran como el Intercambio de Recursos de Origen Cruzado funciona. Todos estos ejemplos utilizan el objeto XMLHttpRequest
, que puede ser utilizado para hacer invocaciones de sitios cruzados en cualquier explorador soportado.
Los fragmentos de JavaScript incluidos en estas secciones (y las instancias ejecutadas del código servidor que correctamente maneja las solicitudes de sitios cruzados) pueden ser encontrados "en acción" aquí, y pueden ser trabajados en exploradores que soportan XMLHttpRequest
de sitios cruzados. Una discusión de Intercambio de Recursos de Origen Cruzado desde una perspectiva de servidor (incluyendo fragmentos de código PHP) puede ser encontrada aquí.
Solicitudes simples
Una solicitud de sitio cruzado es aquella que cumple las siguientes condiciones:
- Los únicos métodos aceptados son:
- GET
- HEAD
- POST.
- Aparte de los encabezados establecidos automáticamente por el agente usuario (ej.
Connection, User-Agent,
etc.), los únicos encabezados que están permitidos para establecer manualmente son:Accept
Accept-Language
Content-Language
Content-Type
- Los únicos valores permitidos del encabezado
Content-Type son:
application/x-www-form-urlencoded
multipart/form-data
text/plain
Por ejemplo, suponga que el contenido web en el dominio https://foo.example
desea invocar contenido en el dominio https://bar.other
. Código de este tipo puede ser utilizado dentro de JavaScript desplegado en foo.example:
var invocation = new XMLHttpRequest(); var url = 'https://bar.other/resources/public-data/'; function callOtherDomain() { if(invocation) { invocation.open('GET', url, true); invocation.onreadystatechange = handler; invocation.send(); } }
Dejándonos ver lo que el explorador enviará al servidor en este caso, y veamos como responde el servidor:
GET /resources/public-data/ HTTP/1.1 Host: bar.other User-Agent: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.1b3pre) Gecko/20081130 Minefield/3.1b3pre Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Accept-Language: en-us,en;q=0.5 Accept-Encoding: gzip,deflate Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7 Connection: keep-alive Referer: https://foo.example/examples/access-control/simpleXSInvocation.html Origin: https://foo.example HTTP/1.1 200 OK Date: Mon, 01 Dec 2008 00:23:53 GMT Server: Apache/2.0.61 Access-Control-Allow-Origin: * Keep-Alive: timeout=2, max=100 Connection: Keep-Alive Transfer-Encoding: chunked Content-Type: application/xml [XML Data]
Las líneas 1 - 10 son los encabezados enviados por Firefox 3.5. Note que el encabezado de solicitud HTTP principal aquí es el Origin:
encabezado en la línea 10 arrina, lo que muestra que la invocación proviene del contenido en el dominio https://foo.example
.
Las líneas 13 - 22 muestran la respuesta HTTP del servidor en el dominio https://bar.other
. En respuesta, el servidor envía de vuelta un encabezado Access-Control-Allow-Origin:
, mostrado arriba en la línea 16. El uso del encabezado Origin:
y Access-Control-Allow-Origin:
muestran el protocolo de control de acceso en su uso más simple. En este caso, el servidor responde con un Access-Control-Allow-Origin: *
lo que significa que el recurso puede ser accesado por cualquier dominio en una forma de sitio cruzado. Si el dueño del recurso en https://bar.other
deseara restringir el acceso al recurso solamente para https://foo.example
, ellos lo enviarían de vuelta:
Access-Control-Allow-Origin: https://foo.example
Note que ahora, ningún otro dominio aparte de https://foo.example
(identificado por el encabezado ORIGIN: en la solicitud, como en la línea 10 arriba) puede accesar al recurso en una forma de sitio cruzado. El encabezado Access-Control-Allow-Origin debe contener el valor que puede enviado en la solicitud del encabezado Origin.
Solicitudes Verificadas
Diferente a solicitudes simples (discutidas arriba), solicitudes "verificadas" envían primero una solicitud HTTP por el método OPTIONS
al recurso en el otro dominio, para determinar si es seguro enviar la verdadera solicitud. Solicitudes de sitios cruzados son verificadas así ya que pueden tener implicaciones en la información de usuario. En particular, una solicitud es verificada sí:
- Usa métodos distintos
a GET, HEAD
o POST
. También, siPOST
es utilizado para enviar solicitudes de información con Content-Type distinto aapplication/x-www-form-urlencoded
,multipart/form-data
, otext/plain
, ej. si la solicitudPOST
envía una carga XML al servidor utilizandoapplication/xml
ortext/xml
, entonces la solicitud es verificada. - Se establecen encabezados personalizados (ej. la solicitud usa un encabezado como
X-PINGOTHER
)
Nota: Empezando en Gecko 2.0, las codificaciones de datos text/plain
, application/x-www-form-urlencoded
, y multipart/form-data
pueden ser enviadas en sitios cruzados sin verificación. Anteriormente, solo text/plain
podía ser enviado sin verificación.
Un ejemplo de este tipo de invocación puede ser:
var invocation = new XMLHttpRequest(); var url = 'https://bar.other/resources/post-here/'; var body = '<?xml version="1.0"?><person><name>Arun</name></person>'; function callOtherDomain(){ if(invocation) { invocation.open('POST', url, true); invocation.setRequestHeader('X-PINGOTHER', 'pingpong'); invocation.setRequestHeader('Content-Type', 'application/xml'); invocation.onreadystatechange = handler; invocation.send(body); } } ......
En el ejemplo de arriba, la línea 3 crea un cuerpo XML para enviar con la solicitud POST
en la línea 8. También, en la línea 9, un encabezado HTTP de solicitud "personalizado" (no estándar) es establecido (X-PINGOTHER: pingpong
). Dichos encabezados no son parte del protocolo HTTP/1.1, pero son útiles generalmente en aplicaciones web. Dado que la solicitud (POST
) usa un Content-Type de application/xml
, y dado que un encabezado personalizado es establecido, la solicitud es verificada.
Veamos este intercambio completo entre un cliente y un servidor:
OPTIONS /resources/post-here/ HTTP/1.1 Host: bar.other User-Agent: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.1b3pre) Gecko/20081130 Minefield/3.1b3pre Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Accept-Language: en-us,en;q=0.5 Accept-Encoding: gzip,deflate Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7 Connection: keep-alive Origin: https://foo.example Access-Control-Request-Method: POST Access-Control-Request-Headers: X-PINGOTHER HTTP/1.1 200 OK Date: Mon, 01 Dec 2008 01:15:39 GMT Server: Apache/2.0.61 (Unix) Access-Control-Allow-Origin: https://foo.example Access-Control-Allow-Methods: POST, GET, OPTIONS Access-Control-Allow-Headers: X-PINGOTHER Access-Control-Max-Age: 1728000 Vary: Accept-Encoding, Origin Content-Encoding: gzip Content-Length: 0 Keep-Alive: timeout=2, max=100 Connection: Keep-Alive Content-Type: text/plain POST /resources/post-here/ HTTP/1.1 Host: bar.other User-Agent: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.1b3pre) Gecko/20081130 Minefield/3.1b3pre Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Accept-Language: en-us,en;q=0.5 Accept-Encoding: gzip,deflate Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7 Connection: keep-alive X-PINGOTHER: pingpong Content-Type: text/xml; charset=UTF-8 Referer: https://foo.example/examples/preflightInvocation.html Content-Length: 55 Origin: https://foo.example Pragma: no-cache Cache-Control: no-cache <?xml version="1.0"?><person><name>Arun</name></person> HTTP/1.1 200 OK Date: Mon, 01 Dec 2008 01:15:40 GMT Server: Apache/2.0.61 (Unix) Access-Control-Allow-Origin: https://foo.example Vary: Accept-Encoding, Origin Content-Encoding: gzip Content-Length: 235 Keep-Alive: timeout=2, max=99 Connection: Keep-Alive Content-Type: text/plain [Some GZIP'd payload]
Las líneas 1 - 12 arriba representan la solicitud verificada con los métodos OPTIONS
. Firefox 3.1 determina lo que se necesita para enviar esto basándose en los parámetros de la solicitud que los fragmentos de JavaScript que se usaron arriba, para que el servidor pueda responder si es aceptable para enviar la solicitud con los parámetros de la solicitud real. OPTIONS es un método HTTP/1.1 que se utilizan para determinar información adicional de los servidores, y es un método idempotente, esto significa que él no puede ser utilizado para cambiar el recurso. Note que junto con la solicitud OPTIONS, otros dos encabezados de solicitud son enviados (líneas 11 y 12 respectivamente):
Access-Control-Request-Method: POST Access-Control-Request-Headers: X-PINGOTHER
El encabezado Access-Control-Request-Method
notifica al servidor como parte de una solicitud verificada cuando la solicitud real es enviada, esta será enviada con un método de solicitud POST
. El encabezado Access-Control-Request-Headers
notifica al servidor que cuando la solicitud actual sea enviada, será enviada con un encabezado X-PINGOTHER
personalizado. Ahora, el servidor tiene la oportunidad para determinar si desea aceptar la solicitud bajo estas circunstancias.
Las líneas 15 - 27 de arriba corresponden con la respuesta que el servidor envía devuelta indicando que el método de la petición (POST) y la cabecera (X-PINGOTHER) son aceptadas. En particular, echemos un vistazo a las líneas
18-21:
Access-Control-Allow-Origin: https://foo.example Access-Control-Allow-Methods: POST, GET, OPTIONS Access-Control-Allow-Headers: X-PINGOTHER Access-Control-Max-Age: 1728000
El servidor responde con Access-Control-Allow-Methods
y dice que POST
, GET
, y OPTIONS
son métodos viables para consultar el recurso en cuestión. Note que este encabezado es similar al HTTP/1.1 Allow: encabezado de respuesta, pero usado estrictamente dentro del contexto del control de acceso. El servidor también envía Access-Control-Allow-Headers
con un valor de X-PINGOTHER
, confirmando que es un encabezado permitido para ser usado en la solicitud real. Como Access-Control-Allow-Methods
, Access-Control-Allow-Headers
es una lista separada por comas de encabezados aceptables. Finalmente, Access-Control-Max-Age
da el valor en segundos para cuánto tarda la respuesta de la solicitud verificada en ser atrapada sin enviar otra solicitud verificada. En este caso, 1728000 segundos son 20 días.
Solicitudes con credenciales
La capacidad más interesante expuesta tanto por XMLHttpRequest
y Access Control es la habilidad para hacer solicitudes "con credenciales" que esten al tanto de Cookies HTTP e información de Autenticación HTTP. Por defecto, en las invocaciones XMLHttpRequest
de un sitio curzado, los exploradores no enviarán credenciales. Una bandera específica tiene que ser establecida en el objeto XMLHttpRequest
cuando este es invocado.
En este ejemplo, el contenido cargado originalmente desde https://foo.example
hace una solicitud GET simple a un recurso en https://bar.other
que establece Cookies. El contenido en foo.example puede contener un JavaScript como este:
var invocation = new XMLHttpRequest(); var url = 'https://bar.other/resources/credentialed-content/'; function callOtherDomain(){ if(invocation) { invocation.open('GET', url, true); invocation.withCredentials = true; invocation.onreadystatechange = handler; invocation.send(); } }
La línea 7 muestra la bandera en XMLHttpRequest
que tiene que ser establecida para poder hacer la invocación con Cookies, es decir, el valor booleano withCredentials
. Por defecto, la invocación es hecha sin Cookies. Dado que esta es una simple solicitud GET
, no es verificada, pero el explorador rechazará cualquier respuesta que no tiene el encabezado Access-Control-Allow-Credentials: true
,y no hará disponible la respuesta para invocar contenido web.
Aquí hay una muestra de intercambio entre un cliente y un servidor:
GET /resources/access-control-with-credentials/ HTTP/1.1 Host: bar.other User-Agent: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.1b3pre) Gecko/20081130 Minefield/3.1b3pre Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Accept-Language: en-us,en;q=0.5 Accept-Encoding: gzip,deflate Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7 Connection: keep-alive Referer: https://foo.example/examples/credential.html Origin: https://foo.example Cookie: pageAccess=2 HTTP/1.1 200 OK Date: Mon, 01 Dec 2008 01:34:52 GMT Server: Apache/2.0.61 (Unix) PHP/4.4.7 mod_ssl/2.0.61 OpenSSL/0.9.7e mod_fastcgi/2.4.2 DAV/2 SVN/1.4.2 X-Powered-By: PHP/5.2.6 Access-Control-Allow-Origin: https://foo.example Access-Control-Allow-Credentials: true Cache-Control: no-cache Pragma: no-cache Set-Cookie: pageAccess=3; expires=Wed, 31-Dec-2008 01:34:53 GMT Vary: Accept-Encoding, Origin Content-Encoding: gzip Content-Length: 106 Keep-Alive: timeout=2, max=100 Connection: Keep-Alive Content-Type: text/plain [text/plain payload]
Pese a que la línea 11 contiene la Cookie destinada para el contenido en https://bar.other
, si bar.other no responde con Access-Control-Allow-Credentials: true
(línea 19) la respuesta será ignorada y no puesta a disposición para el contenido web. Nota Importante: cuando se responde a una solicitud con credeciales, el servidor debe especificar un dominio, y no puede usar comodines. El ejemplo arriba fallará si el encabezado fuera comodín como: Access-Control-Allow-Origin: *
. Dado que Access-Control-Allow-Origin
menciona explícitamente https://foo.example
, el contenido de credenciales competente es retornado al contenido web invocador. Note que en la línea 22, una cookie adicional es establecida.
Todos estos ejemplos pueden verse trabajando aquí. La siguiente sección se refiere a los verdaderos encabezados HTTP.
Los encabezados HTTP de respuesta
Esta sección lista los encabezados HTTP de respuesta que los servidores envían de vuelta para las solicitudes de acceso de control definidas por la especificación del Intercambio de Recursos de Origen Cruzado. La sección anterior da un resumen de estos en acción.
Access-Control-Allow-Origin
Un recurso retornado puede tener un encabezado Access-Control-Allow-Origin
, with con la sintaxis siguiente:
Access-Control-Allow-Origin: <origin> | *
El parámetro origin
específica una URI que puede tener acceso al recurso. El explorador debe asegurar esto. Para solicitudes sin credenciales, el servidor debe especificar "*" como un comodín, de este modo permitiendo a cualquier origin acceder al recurso.
Por ejemplo, para permitir a https://mozilla.com acceder al recurso, usted puede especificar:
Access-Control-Allow-Origin: https://mozilla.com
Si el servidor especifica un host de origin en vez de "*", entonces se debe incluir Origin en el encabezado de respuesta Vary para indicar a los clientes que las respuestas del servidor difieren basándose en el valor del encabezado de respuesta Origin.
Access-Control-Expose-Headers
Requires Gecko 2.0(Firefox 4 / Thunderbird 3.3 / SeaMonkey 2.1)Este encabezado permite una lista blanca de encabezados del servidor que los exploradores tienen permitido accesar. Por ejemplo:
Access-Control-Expose-Headers: X-My-Custom-Header, X-Another-Custom-Header
Esto permite a los encabezados X-My-Custom-Header
y X-Another-Custom-Header
ser expuestos al explorador.
Access-Control-Max-Age
Este encabezado indica durante cuánto tiempo los resultados de la solicitud verificada pueden ser atrapados. Para un ejemplo de solicitudes verificadas, vea los ejemplos de arriba.
Access-Control-Max-Age: <delta-seconds>
El parámetro delta-seconds
indica el número de segundos en que los resultados pueden ser atrapados.
Access-Control-Allow-Credentials
Indica si la respuesta puede ser expuesta cuando la bandera credentials
es verdadera. Cuando se usa como parte de una respuesta para una solicitud verficada, este indica si la solicitud verdadera puede realizarse usando credenciales. Note que solicitudes GET
simples no son verificadas, y por lo que si una solicitud es hecha para un recurso con credenciales, si el encabezado no es retornado con el recurso, la respuesta es ignorada por el explorador y no retornada al contenido web.
Access-Control-Allow-Credentials: true | false
Las Solicitudes con credenciales son discutidas arriba.
Access-Control-Allow-Methods
Específica el método o los métodos permitidos cuando se asigna un recurso. Es usado en respuesta a la solicitud verificada. Las condiciones sobre cuando una solicitud es verificada son discutidas arriba.
Access-Control-Allow-Methods: <method>[, <method>]*
Un ejemplo de una solicitud verificada es dado arriba, incluyendo un ejemplo donde se envía este encabezado al explorador.
Access-Control-Allow-Headers
Usado en respuesta a una solicitud verificada para indicar cual encabezado HTTP puede ser usado cuando se realiza la solicitud real.
Access-Control-Allow-Headers: <field-name>[, <field-name>]*
Los encabezados HTTP de solicitud
Esta sección lista los encabezados que los clietnes deben utilizar cuando cumplen solicitudes HTTP para usar la característica de intercambio de origen cruzado. Note que estos encabezados son establecidos para cuando realizas invocaciones a servidores. Los desarrolladores usan la capacidad de sitios cruzados XMLHttpRequest
para no tener que establecer ninguna solicitud de intercambio de origen cruzado programada.
Origin
Indica el origen de las solicitudes de acceso a sitios cruzados o solicitudes verificadas.
Origin: <origin>
El origen es una URI indicando al servidor de donde la solicitud fue iniciada. Este no incluye ninguna información de recorrido, solo el nombre del servidor.
origin
puede ser un string vacío; esto es útil, por ejemplo, si el recurso es un data
URL.Note que en cualquier solicitud de acceso de control, el encabezado ORIGIN
siempre es enviado.
Access-Control-Request-Method
Usado cuando se emite una solicitud verificada para dejarle saber al servidor cuál método HTTP será usado cuando la solicitud real sea hecha.
Access-Control-Request-Method: <method>
Ejemplos de esta utilización pueden ser encontrados arriba.
Access-Control-Request-Headers
Usada cuanod se emite una solicitud verificada para dejarle saber al servidor cuál encabezado HTTP será usado cuando la solicitud real sea hecha.
Access-Control-Request-Headers: <field-name>[, <field-name>]*
Ejemplos de esta utilización pueden ser encontrados arriba.
Especificaciones
Especificación | Estado | Comentario |
---|---|---|
Fetch The definition of 'CORS' in that specification. |
Living Standard | Nueva definición; tiene como objetivo suplantar la especificación CORS. |
CORS | Recommendation | Definición inicial. |
Compatibilidad con Exploradores
Característica | Chrome | Firefox (Gecko) | Internet Explorer | Opera | Safari |
---|---|---|---|---|---|
Soporte Básico | 4 | 3.5 | 8 (a través de XDomainRequest) 10 |
12 | 4 |
Característica | Android | Chrome para Android | Firefox Mobile (Gecko) | IE Mobile | Opera Mobile | Safari Mobile |
---|---|---|---|---|---|---|
Soporte Básico | 2.1 | yes | yes | ? | 12 | 3.2 |
Nota
Internet Explorer 8 y 9 exponen CORS a través del objeto XDomainRequest, pero tienen una implementación completa en IE 10. Mientras que Firefox 3.5 introduce el soporte para XMLHttpRequests y Web Fonts para sitios cruzados, algunas solicitudes fueron limitadas hasta versiones posteriores. Especificamente, Firefox 7 introduce la habilidad para solicitudes HTTP de sitios cruzados para Texturas WebGL , y Firefox 9 añade soporte para imágenes dibujadas en patrones utilizando drawImage.
Vea también
- Muestras de Código mostrando
XMLHttpRequest
e Intercambio de Recursos de Origen Cruzado - Intercambio de Recursos de Origen Cruzado desde una perspectiva de Servidor (PHP, etc.)
- Especificación del Intercambio de Recursos de Origen Cruzado
XMLHttpRequest
- Discusión adicional sobre el encabezado Origin
- Usando CORS con todos los exploradores (modernos).
- Usando CORS - HTML5 Rocks