O CORS e as solicitações do CORS por meio de seu CDN
O Cross Origin Resource Sharing (CORS) é um mecanismo que é usado pelos navegadores, principalmente para validar permissões para acesso ao conteúdo de uma origem diferente.
O que é CORS?
Quando um navegador carrega uma página da web, ele aplica a Política de mesma origem, o que significa que ele só permite que o conteúdo seja buscado da mesma origem que o da página da web. No entanto, em alguns casos, uma página da web pode precisar de acesso a ativos de diversas origens que confiam nesse website. Aqui é onde o CORS entra.
Esse mecanismo de segurança existirá apenas se um aplicativo tiver ou for um cliente HTTP e se implementar o CORS. Quase todos os navegadores modernos, como Chrome, Firefox e Safari, implementam o CORS.
Para esclarecer, uma origem com relação ao CORS não precisa ser a mesma que uma origem de CDN. Uma origem no CORS é definida por um esquema de URI, um domínio e qualquer número de porta possível. Por exemplo, https://www.example.com:1443
é uma origem diferente de http://www.example.com
. E assim, um CDN também pode ser considerado uma origem do CORS na perspectiva de um navegador.
Como o CORS funciona
O CORS pode lidar com dois tipos de solicitações:solicitações simples e solicitações simuladas, que são mais complexos.
Solicitações simples
Primeira solicitação (acesso ao recurso):
.
Solicitações simples por meio de CORS são solicitações GET
ou POST
da página da Web de uma origem que está tentando obter
acesso à URL de outra origem para recursos
Ao fazer essa solicitação, o navegador automaticamente configura os cabeçalhos de solicitação do CORS. Principalmente, ele configura a origem da página da web fazendo a solicitação no cabeçalho HTTP Origin
automaticamente. A solicitação
CORS também pode conter um conjunto de determinados cabeçalhos HTTP padrão, enquanto mantém seu status como uma solicitação CORS simples, a
partir da perspectiva do navegador.
O servidor que recebe a solicitação do CORS processa a solicitação e pode enviar um conjunto de cabeçalhos de resposta do CORS de volta para o navegador, com o conteúdo solicitado. Esses cabeçalhos de resposta do CORS contêm valores que especificam se a página da web atual tem permissão de acesso a esses recursos, se os cabeçalhos enviados são aceitáveis para essa solicitação e assim por diante.
Se o navegador não conseguir ver sua solicitação do CORS atendida pelos cabeçalhos de resposta do CORS, ele evitará automaticamente o acesso e o carregamento do conteúdo. Caso contrário, ele verá que a origem do CORS está fornecendo permissão para usar o recurso e permitirá o acesso e o carregamento do conteúdo solicitado.
Solicitações simuladas
Primeira solicitação (simulação):
Segunda solicitação (acesso ao recurso):
.
Para uma comunicação CORS mais complexa entre o navegador e uma origem CORS diferente da página da Web solicitante, uma solicitação de simulação é necessária antes de um acesso de recurso real. Certas situações poderão requerer solicitações do CORS de simulação, como métodos de HTTP que não são métodos GET
ou POST
, ou o uso de cabeçalhos de HTTP não padrão
com a solicitação - mesmo se for uma solicitação GET
ou POST
, etc.
Caso uma solicitação de simulação seja necessária, eis como os eventos se desdobram:
- O navegador envia uma solicitação usando o método HTTP OPTIONS para o servidor com todos os cabeçalhos de solicitação de CORS desejados.
- O servidor processa os cabeçalhos de solicitação do CORS e pode responder com cabeçalhos de resposta do CORS não contendo dados reais do conteúdo.
- O navegador verifica os cabeçalhos de resposta do CORS para certificar-se de que a solicitação do CORS seja permitida.
- Se o navegador perceber que a solicitação de recurso desejada deve ser permitida pelo servidor, ele fará uma segunda solicitação para o navegador com o método HTTP desejado, seja
GET
,POST
,PUT
, e assim por diante, com os mesmos cabeçalhos de solicitação do CORS.
Posteriormente, a comunicação entre o navegador e a origem do CORS (diferente daquele da página da web) continuará como se fosse uma solicitação simples do CORS. Semelhante a uma solicitação simples do CORS, o conteúdo e os recursos estarão acessíveis e poderão ser carregados se essa segunda solicitação do CORS for permitida.
Configurando o CORS na sua origem
Conforme mostrado nos diagramas anteriores, o CORS é iniciado pelo cliente HTTP solicitante. No entanto, os efeitos dependem da origem solicitada. Para que seu conteúdo esteja pronto para solicitações do CORS, sua origem deve ser configurada corretamente para responder com os cabeçalhos de resposta do CORS corretos e as permissões de acesso corretas.
O exemplo a seguir mostra uma configuração básica do CORS para um servidor Nginx:
http {
# some http context configs
server {
# some server context configs
# URI path to some content
location /my-static-content {
# some location context configs
# Handle simple requests
#
# Consider only "HTTP GET" requests (content fetching)
if ($request_method = 'GET') {
# Allows the browser to access data from this server during CORS,
# only if the request comes from a web page from the following origin
add_header 'Access-Control-Allow-Origin' 'https://www.example.com';
}
# Handle preflight requests
if ($request_method = 'OPTIONS') {
# Allows the browser to access data from this server during CORS,
# only if the request comes from a web page from the following origin
add_header 'Access-Control-Allow-Origin' 'https://www.example.com';
# Allows only GET requests
add_header 'Access-Control-Allow-Methods' 'GET';
# Allows the following headers in the browser's request headers
# that may have been added by anything other than what the browser had added automatically
add_header 'Access-Control-Allow-Headers' 'pragma';
# Specifies to the browser how long it should cache this preflight response
add_header 'Access-Control-Max-Age' 1728000;
# HTTP 204 response code means success,
# but also that it should expect no content from this (preflight) response
return 204;
}
# more location context configs
# If it is not a complex CORS situation requiring a preflight response,
# then finally attempt to serve the file whose path falls under this location block's URI path match
#
# If no such file is found, then present an HTTP 404 code (not found)
try_files $uri =404;
}
# more server context configs
}
# more http context configs
}
Geralmente, o navegador deve carregar livremente o conteúdo quando vir um Access-Control-Allow-Origin: *
nos cabeçalhos de resposta CORS do servidor de acordo com a especificação w3 referente a esse valor curinga. No entanto, nem todos os navegadores suportam Access-Control-Allow-Origin: *
.
Se o servidor tiver que suportar o acesso de diversas páginas da web, cada uma entregue de uma origem diferente, um único valor de origem para Access-Control-Allow-Origin
deverá ser gerado dinamicamente por solicitação. Veja a seguir
um exemplo básico de tal caso de uso para um servidor Nginx:
http {
# some http context config
######
# Input from $http_origin, the value in Origin HTTP header
# Output to $cors_allowed_origin, a string
#
# Full string match on the Origin header value
#
# Attempt to find a match for the value from $http_origin using regex on the left column.
# If a match is found, then evaluate $cors_allowed_origin to the same value as $http_origin
# Else, default evaluate $cors_allowed_origin to an empty string, so browsers will disallow the CORS request
######
map $http_origin $cors_allowed_origin {
default '';
~^http(s)?://(www|www2|cdn|dev)\.example\.com$ $http_origin;
}
server {
# some server context configs
# URI path to some content
location /my-static-content {
# some location context configs
# Handle simple requests
if ($request_method = 'GET') {
add_header 'Access-Control-Allow-Origin' $cors_allowed_origin;
}
# Handle preflight requests
if ($request_method = 'OPTIONS') {
add_header 'Access-Control-Allow-Origin' '$cors_allowed_origin;
add_header 'Access-Control-Allow-Methods' 'GET';
add_header 'Access-Control-Allow-Headers' 'pragma';
add_header 'Access-Control-Max-Age' 1728000;
return 204;
}
# more location context configs
try_files $uri =404;
}
# more server context configs
}
# more http context configs
}
O exemplo anterior usa a diretiva map
para evitar o uso excessivo da instrução do Nginx if
. Agora, quando uma solicitação do CORS é feita para esse servidor e corresponde a esse caminho de URI, o servidor responde com
o cabeçalho Access-Control-Allow-Origin
contendo o valor http://www.example.com
, https://cdn.example.com
ou http://dev.example.com
, quando o conteúdo é solicitado de http://www.example.com
,
https://cdn.example.com
, http://dev.example.com
e assim por diante.
Configurando o CORS para CDN
O CDN é basicamente transparente para a configuração do CORS da origem, portanto, ele não requer uma configuração específica do CDN. Se o servidor de borda do CDN não puder localizar uma resposta em cache para a primeira solicitação de algum
conteúdo, ele encaminhará a solicitação para o host de origem. Se o host de origem for configurado para tratar das solicitações do CORS e essa solicitação tiver o cabeçalho Origin
, ele deverá responder de volta à borda com um
cabeçalho do CORS de Access-Control-Allow-Origin
, além do valor associado. A resposta geral, incluindo esse cabeçalho e o valor, será armazenada em cache no CDN. Qualquer solicitação subsequente para o objeto no mesmo caminho
de URI é entregue por meio do cache e inclui o valor do cabeçalho Access-Control-Allow-Origin
recebido originalmente da origem.
Suporte para diversas origens do CORS
Em alguns casos, é possível permitir uma lista de origens específicas (não todas) para acessar os conteúdos do CDN e precisar do CDN para entregar cabeçalhos de resposta Access-Control-Allow-Origin
diferentes para origens diferentes
(não curinga *
para qualquer origem). No entanto, o CDN armazena em cache os cabeçalhos junto com os conteúdos, portanto, ele pode entregar o cabeçalho em cache Access-Control-Allow-Origin
para a solicitação, que
pode não corresponder.
É possível utilizar a Otimização de consulta da chave de cache para incluir parâmetros diferentes nas URLs de origens diferentes. Dessa maneira, o conteúdo e os cabeçalhos são armazenados em cache de forma diferente.
Por exemplo, suponha que você tenha configurado o CDN cdn.example.com
para entregar conteúdos para as duas origens (abc.com
e 123.com
) e queira incluir parâmetros diferentes para cada origem, por exemplo,
https://cdn.example.com/test.json?domain=abc.com
e https://cdn.example.com/test.json?domain=123.com
. O CDN retornaria cabeçalhos Access-Control-Allow-Origin
diferentes que são entregues por seu servidor
de back-end:
A solicitação da origem abc.com
retorna access-control-allow-origin: https://abc.com
:
# curl -H "Origin: https://abc.com" -H "Referer: https://abc.com/" -i https://cdn.example.com/test.json?domain=abc.com
HTTP/2 200
access-control-allow-origin: https://abc.com
access-control-allow-methods: GET
access-control-allow-credentials: true
...
A solicitação da origem 123.com
retorna access-control-allow-origin: https://123.com
:
# curl -H "Origin: https://123.com" -H "Referer: https://123.com/" -i https://cdn.example.com/test.json?domain=123.com
HTTP/2 200
access-control-allow-origin: https://123.com
access-control-allow-methods: GET
access-control-allow-credentials: true
...
Resolução de problemas de CORS e de solicitações de CORS
Se seu servidor de origem estiver configurado para o CORS e você não vir o cabeçalho Access-Control-Allow-Origin
retornado à solicitação do navegador, possivelmente o cabeçalho de resposta armazenado em cache no CDN era destinado
a uma solicitação que não tinha o cabeçalho de origem na solicitação. O CDN armazena em cache os cabeçalhos de resposta do host de origem. No entanto, os cabeçalhos em cache se baseiam na solicitação que acionou a solicitação para a origem.
Nesse caso, os cabeçalhos de resposta podem não incluir os cabeçalhos do CORS. Limpe o cache no CDN para esse caminho usando a funcionalidade de limpeza do CDN e tente a solicitação por meio do cliente novamente.
O cabeçalho de resposta Vary
do seu servidor de origem também pode causar um comportamento inesperado ao buscar conteúdo por meio do CDN. Diferentemente de uma exceção específica, o CDN não armazenará em cache o conteúdo (e o respectivo
cabeçalho de resposta associado) de seu servidor de origem se o servidor responder com um cabeçalho Vary
. Atualmente, nosso serviço removerá o cabeçalho Variar da origem para renderizar o objeto armazenável em cache, se o objeto
for um dos tipos de arquivo a seguir: aif, aiff, au, avi, bin, bmp, cab, carb, cct, cdf, class, css, doc, dcr, dtd, exe, flv, gcf, gff, gif, grv, hdml, hqx, ico, ini, jpeg, jpg, js, mov, mp3, nc, pct, pdf, png, ppc, pws, swa, swf, txt, vbs, w32, wav, wbmp, wml, wmlc, wmls, wmlsc, xsd, zip, webp, jxr, hdp, wdp, pict, tif, tiff, mid, midi, ttf, eot, woff, otf, svg, svgz, jar, woff2, json
.
Se o objeto a ser armazenado em cache não for um desses tipos de arquivo, remova o cabeçalho Vary
da resposta do servidor de origem para esse objeto e tente novamente depois de usar as funções de limpeza do CDN.