# Cross-Origin Resource Sharing (CORS) --- ## Para acompanhar a apresentação ![](https://i.imgur.com/Woodtmi.png) --- Mecanismo que trabalha via HTTP headers para permitir que aplicações web rodando em uma origem tenham acesso a recursos em outra origem. --- Por motivos de segurança, os browsers restringem requests para destinos diferentes da origem --- Essas restrições possuem regras bem definidas e se soubermos exatamente quais são elas e como trata-las, evitamos o famigerado "Erro de CORS" --- ## Como isso funciona? --- Requests de origens diferentes são separados em dois grupos principais: Requests Simples e Preflighted Requests --- ### Requests Simples --- Requests que não ativam o CORS preflight são chamados de Requests Simples. --- Para determinar se um request é simples, ele deve atender a TODOS os critérios a seguir --- #### Métodos: - GET - POST - HEAD --- #### Headers personalizados podem ser apenas: - Accept - Accept-Language - Content-Language - Content-Type - Valores podem ser apenas - application/x-www-form-urlencoded - multipart/form-data - text/plain --- #### Headers personalizados podem ser apenas: - DPR - Downlink - Save-Data - Viewport-Width - Width --- Caso o request se enquadre em todos esses requisitos, o único requisito no response do servidor é o header Access-Control-Allow-Origin (onde o valor pode ser um domínio específico ou *) --- ```javascript const invocation = new XMLHttpRequest(); const url = 'http://bar.other/resources/public-data/'; function callOtherDomain() { if (invocation) { invocation.open('GET', url, true); invocation.onreadystatechange = handler; invocation.send(); } } ``` --- ![](https://i.imgur.com/9xMdgZB.png) --- ``` 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] ``` --- Caso o request NÃO se enquadre nessas regras, um preflight request será executado --- ### Preflighted Requests --- Ao contrário dos requests simples, os preflighted requests primeiro enviam um outro request para validar se o request original é seguro de ser enviado --- Isso acontece em requests para domínios diferentes, pois o request pode ter implicações em dados dos usuários --- Um request preflight é um request com o método OPTIONS para o mesmo recurso do request original --- ```javascript const invocation = new XMLHttpRequest(); const url = 'http://bar.other/resources/post-here/'; const 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); } } ``` --- ![](https://i.imgur.com/YAUEhrr.png) --- ``` 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 204 No Content 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 Keep-Alive: timeout=2, max=100 Connection: Keep-Alive ``` --- Após o preflight request retornar, o browser valida se o request original pode ser enviado. Se sim, ele o faz --- ``` 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] ``` --- #### Requests com Credenciais --- Uma excelente feature do XMLHttpRequest ou Fetch é a capacidade de enviar requests "credenciados", ou seja, requests com cookies ou headers de autenticação --- Por padrão, requests XMLHttpRequest ou Fetch para domínios diferentes não enviam credenciais --- Para enviar credenciais num request XMLHttpRequest ou Fetch para um domínio diferente, é necessário definir uma flag específica `withCredentials` --- ```javascript const invocation = new XMLHttpRequest(); const url = 'http://bar.other/resources/credentialed-content/'; function callOtherDomain() { if (invocation) { invocation.open('GET', url, true); invocation.withCredentials = true; invocation.onreadystatechange = handler; invocation.send(); } } ``` --- ![](https://i.imgur.com/OEfi7PT.png) --- ``` 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] ``` --- Para requests com credenciais, o response deve OBRIGATORIAMENTE retornar o header Access-Control-Allow-Origin com um domínio específico (e não um wildcard ), assim como o header Access-Control-Allow-Credentials --- ## Referências --- Boa parte (ou quase tudo) isso que eu falei, pode ser encontrado com mais detalhes em https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS --- # :100: :muscle: :tada: Chega de sofrer com CORS! --- ### Obrigado :sheep:
{"metaMigratedAt":"2023-06-14T22:31:33.313Z","metaMigratedFrom":"YAML","title":"Cross-Origin Resource Sharing (CORS)","breaks":true,"description":"View the slide with \"Slide Mode\".","contributors":"[{\"id\":\"3d08152e-fd09-4008-ac70-e1ee81063eae\",\"add\":10790,\"del\":2807}]"}
    381 views