Esta tradução está incompleta. Por favor, ajude a traduzir este artigo.

Compartilhamento de recursos de origens cruzadas é um mecanismo que usa cabeçalhos HTTP adicionais para garantir permissão de acesso a recursos de um servidor diferente do da origem da página (domínio) correntemente em uso. Um user agent realiza um requisição HTTP de origem cruzada quando executa uma requisição de um domínio, protocolo ou porta diferente do qual originou o documento corrente.
 
Um exemplo de requisição de origem cruzada: Uma pagina HTML acessada através de http://domain-a.com faz requisição de uma imagem <img> src para http://domain-b.com/image.jpg. Muita páginas na web, hoje em dia, utilizam recursos como CSS stylesheets, imagens e scripts de um domínio diferente do que originou a página corrente, como redes de entrega de conteúdo (CDN).
 

Por razões de segurança, os navegadores restringem solicitações HTTP de origem cruzada iniciadas a partir de scripts. Por exemplo, XMLHttpRequest e Fetch seguem a política de mesma origem. Assim, um aplicativo da web usando XMLHttpRequest ou Fetch só poderá fazer solicitações HTTP para seu próprio domínio. Para melhorar os aplicativos da Web, os desenvolvedores solicitaram que os fornecedores de navegador permitissem solicitações entre domínios.

 

O mecânismo de Compartilhamento de Recursos entre Origens (CORS) fornece aos servidores de web controles de acesso entre domínios, que permitem transferências seguras de dados entre domínios. Os navegadores modernos usam o CORS em um container API - como XMLHttpRequest ou Fetch - Para mitigar os riscos de pedidos HTTP de origem cruzada.

Este artigo destina-se a administradores da Web, desenvolvedores de servidores e desenvolvedores front-end. Os navegadores modernos lidam com os componentes do lado do cliente do compartilhamento entre origens, incluindo cabeçalhos e aplicação de políticas. Mas esse novo padrão significa que os servidores precisam lidar com novos cabeçalhos de solicitação e resposta. Outro artigo para desenvolvedores de servidores que discutem compartilhamento de origem cruzada a partir de uma perspectiva de servidor (com fragmentos de código PHP). Esta é uma leitura complementar.

Esse padrão de compartilhamento de origem cruzada é usado para habilitar solicitações de HTTP entre sites para:

Este artigo é uma discussão geral do Compartilhamento de Recursos entre Origens (CORS) e inclui uma discussão dos cabeçalhos HTTP necessários.

Visão Geral

O padrão de Compartilhamento de Recursos entre Origens (CORS) trabalha adicionando novos cabeçalhos HTTP que permitem que o servidor descreva o conjunto de origens que são permitidas a ler essa informação usando um navegador web.  Além disso, para métodos de requisição HTTP que podem causar efeitos colaterais nos dados do servidor (em particular, para métodos HTTP que não sejam GET, ou para utilização de GET com certos MIME types), a especificação delega que navegadores "pré-enviem" a requisição, solicitando os métodos suportados pelo servidor com um método de requisição HTTP OPTIONS, e depois, após "aprovação" do servidor, envie a requisição verdadeira com o método de requisição HTTP efetivo. Servidores também podem notificar clientes se "credenciais" (incluindo Cookies e informações de HTTP Authentication) devem ser enviadas com as requisições.

Falhas em CORS resultam em erros, mas por questões de segurança os detalhes dos erros não estão disponíveis no código JavaScript. O código tem apenas conhecimento de que ocorreu um erro. A única maneira para determinar especificamente o que ocorreu de errado é olhando no console do browser para mais detalhes.

Seções subsequentes discutem cenários, assim como provêem a decomposição dos cabeçalhos HTTP utilizados. 

Exemplos de cenários de controle de acesso

Aqui, apresentamos três cenários que ilustram como o Compartilhamento de Recursos entre Origens funciona. Todos estes exemplos usam o objeto XMLHttpRequest, que pode ser utilizado para fazer requisições entre origens em qualquer navegador compatível.

Os snippets JavaScript inclusos nessas seções (e instâncias executáveis do código no servidor que tratam corretamente essas requisições entre origens) podem ser encontradas "em ação" aqui, e irão funcionar em navegadores que suportam XMLHttpRequest entre origens.

Uma discussão sobre Compartilhamento de Recursos entre Origens a partir da perspectiva do servidor (incluindo snippets de código PHP) podem ser encontradas aqui.

Requisições simples

Algumas requisições não desencadeiam um pré-envio CORS. Essas são denominadas  “requisições simples” neste artigo, embora a especificação Fetch (que define CORS) não utilize este termo. Uma requisição que não desencadeia um pré-envio CORS—denominada “requisição simples”—é uma que atende todas as seguintes condições:

Nota: Estes são os mesmos tipos de requisições de origem cruzada que o conteúdo web já pode realizar, e nenhum dado dado de resposta é liberado ao solicitante a menos que o servidor envie um cabeçalho adequado. Portanto, sites que impedem a falsificação de requisições entre origens não tem nada a temer em relação ao controle de acesso HTTP.
Nota: O WebKit Nightly e Safari Technology Preview impõem restrições adicionais nos valores permitidos nos cabeçalhos Accept, Accept-Language, e Content-Language. Caso algum destes cabeçalhos tenham valores ”não-padronizados”, o WebKit/Safari não considera que a requisição atenda as condições para uma “requisição simples”. O que o WebKit/Safari considera valores “não-padronizados” para estes cabeçalhos não é documentado exceto nos seguintes bugs do WebKit: Require preflight for non-standard CORS-safelisted request headers Accept, Accept-Language, and Content-Language, Allow commas in Accept, Accept-Language, and Content-Language request headers for simple CORS, e Switch to a blacklist model for restricted Accept headers in simple CORS requests. Nenhum outro navegador implementa estas restrições extras, pois elas não são parte da especificação.

Por exemplo, suponha que o conteúdo web no domínio http://foo.example deseje invocar um outro conteúdo no domínio http://bar.other. Códigos como este podem ser usados com o Javascript hospedado em 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(); 
  }
}

Isso fará uma simples troca entre o cliente e o servidor, utilizando cabeçalhos CORS para o tratamento de privilégios.

Vamos ver o que o browser enviará para o servidor neste caso, e vamos ver como o servidor responde:

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]

Linhas 1 - 10 são enviadas no header. Note que o principal header da requisição HTTP de importancia aqui é Origin header na linha 10 acima, o qual mostra que a invocação advém do conteúdo no domínio http://foo.example.

Linhas 13 - 22 mostram a resposta HTTP do servidor no domínio http://bar.other. Em resposta, é enviado de volta um header Access-Control-Allow-Origin exibido acima na linha 16. O uso dos headers Origin e Access-Control-Allow-Origin mostram o protocolo de controle de acesso em seu uso mais simples. Neste caso, o servidor responde com Access-Control-Allow-Origin: * o que significa que o recurso pode ser acessado por qualquer dominio de uma maneira cross-site. Se os donos do recurso em http://bar.other desejarem restringir o acesso ao recurso para o mesmo vir apenas de http://foo.example, eles retornaram:

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

Note que agora, nenhum dominio além de http://foo.example (identificado na requisição pelo header ORIGIN: como na linha 10 acima) pode acessar o recurso de uma maneira cross-site. O header Access-Control-Allow-Origin deve conter o valor que foi enviado no header Origin da requisição. 

Requisições pré-enviadas

Ao contrário de “requisições simples” (discutido acima), requisições "pré-enviadas" primeiro enviam uma requisição HTTP através do método OPTIONS para o recurso no outro domínio, para determinar se de fato a requisição atual é segura para envio. Requisições cross-site são pre-enviadas desta maneira já que elas podem ter implicações para os dados do usuário.

Em particular, uma requisição é pré-enviada se qualquer uma das seguintes condições for verdadeira:

Nota: WebKit Nightly e Safari Technology Preview colocam restrições adicionais nos valores permitidos dos cabeçalhos Accept, Accept-Language, e Content-Language. Caso qualquer desses cabeçalhos tiver valores fora do padrão (non-standard), WebKit/Safari pré-envia a requisição. O que WebKit/Safari considera como valor “non-standard” para tais cabeçalhos não é documentado, fora nos bugs WebKit a seguir: Require preflight for non-standard CORS-safelisted request headers Accept, Accept-Language, and Content-Language, Allow commas in Accept, Accept-Language, e Content-Language request headers for simple CORS, and Switch to a blacklist model for restricted Accept headers in simple CORS requests. Nenhum outro browser implementa tais restrições extras, pois elas não fazem parte da especificação.

O exemplo a seguir é de uma requisição que será pré-enviada.

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); 
    }
}

......

No exemplo acima, a linha 3 cria um corpo XML a ser enviado com a requisição POST na linha 8.  Também, na linha 9, é definida um cabeçalho de uma requisição (non-standard) HTTP "pesonalizada" com (X-PINGOTHER: pingpong).  Tais cabeçalhos não fazem parte do protocolo HTTP/1.1, mas são geralmente usados para aplicações web.  Já que a requisição usa um Content-Type do tipo application/xml, e como uma requisição personalizada é definida, esta requisição é pré-enviada.

Vamos conferir a completa troca que ocorre entre cliente e servidor. A primeira troca é a requisição pré-envio/resposta:

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, Content-Type


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, Content-Type
Access-Control-Max-Age: 86400
Vary: Accept-Encoding, Origin
Content-Encoding: gzip
Content-Length: 0
Keep-Alive: timeout=2, max=100
Connection: Keep-Alive
Content-Type: text/plain

Uma vez que a requisição pré-envio é completa, a requisição efetiva é enviada:

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]

Linhas 1 - 12 acima representam a requisição pré-envio com o método OPTIONS. O browser determinase é necessário enviá-lo baseado nos parâmetros da requisição que o código JavaScript acima utiliza, para que o servidor possa responder caso seja aceitável o envio da requisição com os dados parâmetros da mesma. OPTIONS é um método HTTP/1.1 utilizado para determinar informações complementares dos servidores, sendo o mesmo um método safe, o que significa que não pode ser utilizado para troca de recurso. Note que junto da requisição OPTIONS, outros dois cabeçalhos são enviados (linhas 10 e 11, respectivamente):

Access-Control-Request-Method: POST
Access-Control-Request-Headers: X-PINGOTHER, Content-Type

O cabeçalho Access-Control-Request-Method notifica o servidor como sendo uma parte da requisição pré-envio que, quando a requisição efetiva é enviada, será enviada com uma requisição de método POST. O cabeçalho Access-Control-Request-Headers notifica o servidor que quando a requisição efetiva fora enviada, será enviada com os seguintes cabeçalhos personalizados X-PINGOTHER e Content-Type. O servidor agora tem oportunidade para definir se deseja aceitar uma requisição sob estas condições.

Linhas 14 - 26 acima são a resposta que o servidor devolve, indicando que o método (POST) e ocabeçalho (X-PINGOTHER) da requisição são aceitáveis. Em particular, vejamos as linhas 17-20:

Access-Control-Allow-Origin: http://foo.example
Access-Control-Allow-Methods: POST, GET, OPTIONS
Access-Control-Allow-Headers: X-PINGOTHER, Content-Type
Access-Control-Max-Age: 86400

O servidor responde com Access-Control-Allow-Methods e diz que POST, GET, e OPTIONS são métodos viáveis para requerir o recurso em questão. Perceba que este cabeçalho é similar ao cabeçalho da resposta Allow, mas usado estritamente dentro do contexto do controle de acesso.

O servidor envia também Access-Control-Allow-Headers com um valor de "X-PINGOTHER, Content-Type", confirmando estes são cabeçalhos permitidos a serem usados com a requisição efetiva. Assim como Access-Control-Allow-Methods, Access-Control-Allow-Headers é uma lista de cabeçalhos aceitáveis, separados por vírgula.

Por fim, Access-Control-Max-Age traz o valor em segundos de quão longo pode ser mantida em cache a resposta da requisição pré-envio sem o envio de outra requisição pré-envio. Neste caso, 86400 segundos são 24 horas. Note que cada browser tem um valor interno máximo que toma precedência quado Access-Control-Max-Age for maior.

Requisições com credenciais

The most interesting capability exposed by both XMLHttpRequest or Fetch and CORS is the ability to make "credentialed" requests that are aware of HTTP cookies and HTTP Authentication information. By default, in cross-site XMLHttpRequest or Fetch invocations, browsers will not send credentials. A specific flag has to be set on the XMLHttpRequest object or the Request constructor when it is invoked.

In this example, content originally loaded from http://foo.example makes a simple GET request to a resource on http://bar.other which sets Cookies. Content on foo.example might contain JavaScript like this:

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(); 
  }
}

Line 7 shows the flag on XMLHttpRequest that has to be set in order to make the invocation with Cookies, namely the withCredentials boolean value. By default, the invocation is made without Cookies. Since this is a simple GET request, it is not preflighted, but the browser will reject any response that does not have the Access-Control-Allow-Credentials: true header, and not make the response available to the invoking web content.

Here is a sample exchange between client and server:

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]

Although line 11 contains the Cookie destined for the content on http://bar.other, if bar.other did not respond with an Access-Control-Allow-Credentials: true (line 19) the response would be ignored and not made available to web content.

Solicitações credenciadas e curingas (wildcards)

When responding to a credentialed request, the server must specify an origin in the value of the Access-Control-Allow-Origin header, instead of specifying the "*" wildcard.

Because the request headers in the above example include a Cookie header, the request would fail if the value of the Access-Control-Allow-Origin header were "*". But it does not fail: Because the value of the Access-Control-Allow-Origin header is "http://foo.example" (an actual origin) rather than the "*" wildcard, the credential-cognizant content is returned to the invoking web content.

Note that the Set-Cookie response header in the example above also sets a further cookie. In case of failure, an exception—depending on the API used—is raised.

All of these examples can be seen working here. The next section deals with the actual HTTP headers.

Os cabeçalhos de resposta HTTP

This section lists the HTTP response headers that servers send back for access control requests as defined by the Cross-Origin Resource Sharing specification. The previous section gives an overview of these in action.

Access-Control-Allow-Origin

A returned resource may have one Access-Control-Allow-Origin header, with the following syntax:

Access-Control-Allow-Origin: <origin> | *

The origin parameter specifies a URI that may access the resource. The browser must enforce this. For requests without credentials, the server may specify "*" as a wildcard, thereby allowing any origin to access the resource.

For example, to allow http://mozilla.org to access the resource, you can specify:

Access-Control-Allow-Origin: http://mozilla.org

If the server specifies an origin host rather than "*", then it could also include Origin in the Vary response header to indicate to clients that server responses will differ based on the value of the Origin request header.

Access-Control-Expose-Headers

The Access-Control-Expose-Headers header lets a server whitelist headers that browsers are allowed to access. For example:

Access-Control-Expose-Headers: X-My-Custom-Header, X-Another-Custom-Header

This allows the X-My-Custom-Header and X-Another-Custom-Header headers to be exposed to the browser.

Access-Control-Max-Age

The  Access-Control-Max-Age header indicates how long the results of a preflight request can be cached. For an example of a preflight request, see the above examples.

Access-Control-Max-Age: <delta-seconds>

The delta-seconds parameter indicates the number of seconds the results can be cached.

Access-Control-Allow-Credentials

The Access-Control-Allow-Credentials header Indicates whether or not the response to the request can be exposed when the credentials flag is true.  When used as part of a response to a preflight request, this indicates whether or not the actual request can be made using credentials. Note that simple GET requests are not preflighted, and so if a request is made for a resource with credentials, if this header is not returned with the resource, the response is ignored by the browser and not returned to web content.

Access-Control-Allow-Credentials: true

Credentialed requests are discussed above.

Access-Control-Allow-Methods

The Access-Control-Allow-Methods header specifies the method or methods allowed when accessing the resource. This is used in response to a preflight request. The conditions under which a request is preflighted are discussed above.

Access-Control-Allow-Methods: <method>[, <method>]*

An example of a preflight request is given above, including an example which sends this header to the browser.

Access-Control-Allow-Headers

The Access-Control-Allow-Headers header is used in response to a preflight request to indicate which HTTP headers can be used when making the actual request.

Access-Control-Allow-Headers: <field-name>[, <field-name>]*

Os cabeçalhos de solicitação HTTP

This section lists headers that clients may use when issuing HTTP requests in order to make use of the cross-origin sharing feature. Note that these headers are set for you when making invocations to servers. Developers using cross-site XMLHttpRequest capability do not have to set any cross-origin sharing request headers programmatically.

Origin

The Origin header indicates the origin of the cross-site access request or preflight request.

Origin: <origin>

The origin is a URI indicating the server from which the request initiated.  It does not include any path information, but only the server name.

Note: The origin can be the empty string; this is useful, for example, if the source is a data URL.

Note that in any access control request, the Origin header is always sent.

Access-Control-Request-Method

The Access-Control-Request-Method is used when issuing a preflight request to let the server know what HTTP method will be used when the actual request is made.

Access-Control-Request-Method: <method>

Examples of this usage can be found above.

Access-Control-Request-Headers

The Access-Control-Request-Headers header is used when issuing a preflight request to let the server know what HTTP headers will be used when the actual request is made.

Access-Control-Request-Headers: <field-name>[, <field-name>]*

Examples of this usage can be found above.

Especificações

Specification Status Comment
Fetch
The definition of 'CORS' in that specification.
Padrão em tempo real New definition; supplants CORS specification.
Unknown Desconhecido Initial definition.

Estamos convertendo nossos dados de compatibilidade para o formato JSON. Esta tabela de compatibilidade ainda usa o formato antigo, pois ainda não convertemos os dados que ela contém. Descubra como você pode ajudar!

Feature Chrome Firefox (Gecko) Internet Explorer Opera Safari
Basic support 4 3.5 8 (via XDomainRequest)
10
12 4
Feature Android Chrome for Android Firefox Mobile (Gecko) IE Mobile Opera Mobile Safari Mobile
Basic support 2.1 yes yes ? 12 3.2

Notas de compatibilidade

  • Internet Explorer 8 and 9 expose CORS via the XDomainRequest object, but have a full implementation in IE 10. 
  • While Firefox 3.5 introduced support for cross-site XMLHttpRequests and Web Fonts, certain requests were limited until later versions. Specifically, Firefox 7 introduced the ability for cross-site HTTP requests for WebGL Textures, and Firefox 9 added support for Images drawn on a canvas using drawImage.

Veja também

Etiquetas do documento e colaboradores

Etiquetas: 
Última atualização por: rbuzatto,