Mozilla's getting a new look. What do you think? https://mzl.la/brandsurvey

Control de acceso HTTP (CORS)

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 http://domain-a.com hace una solicitud <img> src a http://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:

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
Nota: Estos son los mismos tipos de solicitud de sitios cruzados que un contenido web ya puede emitir, y ninguna respuesta de datos es liberada a menos que el servidor envíe el encabezado apropiado. Por lo tanto, sitios que prevengan solicitudes falsas de sitios cruzados no tienen nada nuevo que temer sobre el control de acceso HTTP.

Por ejemplo, suponga que el contenido web en el dominio http://foo.example desea invocar contenido en el dominio http://bar.other. Código de este tipo puede ser utilizado dentro de JavaScript desplegado en foo.example:

var invocation = new XMLHttpRequest();
var url = 'http://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: http://foo.example/examples/access-control/simpleXSInvocation.html
Origin: http://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 http://foo.example.

Las líneas 13 - 22  muestran la respuesta HTTP del servidor en el dominio http://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 http://bar.other deseara restringir el acceso al recurso solamente para http://foo.example, ellos lo enviarían de vuelta:

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

Note que ahora, ningún otro dominio aparte de http://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, si POST es utilizado para enviar solicitudes de información con Content-Type distinto a application/x-www-form-urlencoded, multipart/form-data, o text/plain, ej. si la solicitud POST envía una carga XML al servidor utilizando application/xml or text/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 = 'http://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: http://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: http://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: http://foo.example/examples/preflightInvocation.html
Content-Length: 55
Origin: http://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: http://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: http://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 http://foo.example hace una solicitud GET simple a un recurso en http://bar.other que establece Cookies.  El contenido en foo.example puede contener un JavaScript como este:

var invocation = new XMLHttpRequest();
var url = 'http://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: http://foo.example/examples/credential.html
Origin: http://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: http://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 http://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 http://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 http://mozilla.com acceder al recurso, usted puede especificar:

Access-Control-Allow-Origin: http://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. 

Nota: El 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

Etiquetas y colaboradores del documento

 Colaboradores en esta página: aurigadl, dcruz, Manhru, maedca
 Última actualización por: aurigadl,