--- title: Cross-Origin Resource Sharing (CORS) slug: Web/HTTP/CORS tags: - AJAX - CORS - Controllo accessi HTTP - Cross-Origin Resource Sharing - Fetch - Fetch API - HTTP - Same-origin policy - Security - Sicurezza - XMLHttpRequest translation_of: Web/HTTP/CORS ---
Il Cross-Origin Resource Sharing ({{Glossary("CORS")}}) è un meccanismo che usa header {{Glossary("HTTP")}} addizionali per indicare a un browser che un'applicazione Web in esecuzione su un'origine (dominio) dispone dell'autorizzazione per accedere alle risorse selezionate da un server di origine diversa. Un'applicazione web invia una cross-origin HTTP request quando richiede una risorsa che ha un'origine (protocollo, dominio e porta) differente dalla propria.
Esempio di cross-origin request: Il codice Javascript di frontend per un'applicazione web servita da http://domain-a.com
utilizza {{domxref("XMLHttpRequest")}} per inviare una richiesta a http://api.domain-b.com/data.json
.
Per ragioni di sicurezza, i browser limitano le cross-origin HTTP requests che vengono generate all'interno degli scripts. Ad esempio, XMLHttpRequest
e la Fetch API seguono la same-origin policy. Ciò significa che un'applicazione web che utilizza queste API può solamente richiedere risorse HTTP dalla stessa origine di caricamento dell'applicazione, a meno che la risposta dall'altra origine includa i corretti header CORS.
Il meccanismo CORS supporta richieste e trasferimenti dati sicuri fra browsers e web servers. I browser moderni usano CORS in container API come XMLHttpRequest
o Fetch per aiutare a mitigare i rischi di richieste HTTP cross-origin.
Tutti, davvero.
Più specificamente, questo articolo è per amministratori web, sviluppatori server side e front end. I browser moderni gestiscono i componenti client della cross-origin sharing, inclusi gli headers e applicazione delle policy. Ma questo nuovo standard richiede che i server gestiscano nuovi headers di richiesta e risposta. Un altro articolo per sviluppator server side che discute la cross-origin sharing da una prospettiva server (con esempi di codice PHP ) è una lettura supplementare.
Questo cross-origin sharing standard è usato per abilitare richieste HTTP cross-site per:
@font-face
all'interno di regole CSS), così che i server possano esporre fonts TrueType che possano essere caricati ed usati in modalità cross-site solo da siti web a cui è stata concessa l'autorizzazione per farlo.Questo articolo è una discussione generale sul Cross-Origin Resource Sharing e include una trattazione degli header HTTP necessari.
Lo standard Cross-Origin Resource Sharing funziona aggiungendo nuovi header HTTP che consentono ai server di descrivere l'insieme di origini che sono autorizzate a leggere quelle informazioni tramite un web browser. In aggiunta, per i metodi di richiesta HTTP che possono causare effetti collaterali sui dati del server (in particolare, per i metodi HTTP diversi da {{HTTPMethod("GET")}}, o per l'utilizzo di {{HTTPMethod("POST")}} con determinati MIME types), la specifica prevede che il browser "anticipi" la richiesta (questa operazione è detta "preflight"), richiedendo al server i metodi supportati tramite una richiesta HTTP {{HTTPMethod("OPTIONS")}}, e poi, dopo una "approvazione" del server, invii la richiesta effettiva con il metodo HTTP effettivo. I server possono anche informare i client se delle "credenziali" (inclusi Cookies e dati di autenticazione HTTP) debbano essere inviate insieme alle richieste.
Gli insuccessi CORS generano degli errori, ma per ragioni di sicurezza, i dettagli riguardo a cosa sia andato male non sono disponibili al codice JavaScript. Tutto ciò che il codice può sapere è che si è verificato un errore. L'unico modo per determinare cosa sia andato male nello specifico è guardare la console del browser per i dettagli.
Le sezioni successive discutono alcuni scenari, e provvedono un'analisi dettagliata degli header HTTP usati.
Qui presentiamo tre scenari che illustrano come funziona la Cross-Origin Resource Sharing. Tutti questi esempi utilizzano l'oggetto {{domxref("XMLHttpRequest")}}, che può essere usato per creare chiamate cross-site in qualsiasi browser che le supporti.
Gli spezzoni di codice JavaScript inclusi in queste sezioni (e istanze attive di codice server che gestiscono correttamente queste richieste cross-site) possono essere viste in azione su http://arunranga.com/examples/access-control/, e funzioneranno nei browser che supportano XMLHttpRequest
cross-site.
Una trattazione della Cross-Origin Resource Sharing da una prospettiva server (inclusi spezzoni di codice PHP) si possono trovare nell'articolo Server-Side Access Control (CORS).
Alcune richieste non scatenano una CORS preflight. Queste sono chiamate “richieste semplici” in questo articolo, anche se la specifica {{SpecName('Fetch')}} (che definisce CORS) non utilizza quel termine. Una richiesta che non scatena una CORS preflight—una cosiddetta “richiesta semplice”—è una richiesta che soddisfa tutte le seguenti condizioni:
DPR
Save-Data
Viewport-Width
Width
application/x-www-form-urlencoded
multipart/form-data
text/plain
Per esempio, supponiamo che una pagina web su dominio http://foo.example
tenti di accedere a contenuto su dominio http://bar.other
. In Javascript, verrebbe scritto un codice simile al seguente in 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(); } }
Tutto ciò porterà ad un semplice scambio di informazioni tra client e server, usando headers CORS per manipolare i privilegi:
Vediamo cosa il browser manderà al server in questo caso, e come risponderà il server:
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 [Dati XML]
Le linee 1 - 10 sono gli header mandati. L'header più importante qui è {{HTTPHeader("Origin")}} alla linea 10, che mostra che l'invocazione origina dal dominio http://foo.example
.
Le linee 13 - 22 mostrano la risposta HTTP dal server al dominio http://bar.other
. In risposta, il server manda un header {{HTTPHeader("Access-Control-Allow-Origin")}} mostrato nella linea 16. L'uso dell'header {{HTTPHeader("Origin")}} e {{HTTPHeader("Access-Control-Allow-Origin")}} dimostrano il protocollo di controllo accesso nella sua forma più semplice. In questo caso, il server risponde con Access-Control-Allow-Origin: *
il che significa che la risorsa può essere acceduta da qualsiasi dominio. Se i proprietary della risorsa su http://bar.other
vogliono restringere accesso alla risorsa alle sole richieste provenienti da http://foo.example
, risponderebbero con:
Access-Control-Allow-Origin: http://foo.example
Nota che ora, nessun dominio a parte http://foo.example
(identificato dall'header ORIGIN: nella richiesta, come nella linea 10) può accedere alla risorsa in maniera cross-site. L'header Access-Control-Allow-Origin
deve contenere il valore che è stato mandato nell'header Origin
della richiesta.
Al contrario delle "richieste semplici" discusse sopra, le richieste "in preflight" (anticipate) mandano prima una richiesta HTTP tramite il metodo {{HTTPMethod("OPTIONS")}} alla risorsa nell'altro dominio, per determinare se la richiesta vera e propria è sicura. Richieste cross-site vengono anticipate in questo modo perché potrebbero avere implicazioni per la sicurezza dei dati utenti.
In particolare, una richiesta è anticipate se anche solo una delle seguenti condizioni è vera:
DPR
Save-Data
Viewport-Width
Width
application/x-www-form-urlencoded
multipart/form-data
text/plain
Il seguente è un esempio di una richiesta che verrà effettuata in preflight.
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); } } ......
Nell'esempio sopra, la linea 3 crea un corpo XML che viene mandato con una richiesta POST
alla linea 8. Nella linea 9 viene specificato un header "non-standard" (X-PINGOTHER: pingpong
). Questi headers non fanno parte del protocollo HTTP/1.1, ma sono utili per applicazioni web. La richiesta è eseguita in preflight perché usa un Content-Type di application/xml
e la richiesta usa un header non-standard.
(Nota: come descritto sopra, la richiesta POST non include gli header Access-Control-Request-*; questi sono necessari solo per le richieste OPTIONS.)
Diamo un'occhiata allo scambio complete tra client e server. Il primo scambio è la richiesta e risposta in preflight:
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 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
Quando la richiesta in preflight è completa, la richiesta vera e propria viene mandata:
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 [Payload compresso con GZIP]
Le linee 1 - 12 sopra rappresentano le richieste in preflight con il metodo {{HTTPMethod("OPTIONS")}}. Il browser determina che deve mandare questo in base ai parametri della prima richiesta. OPTIONS è un metodo HTTP/1.1 usato per ricevere informazioni aggiuntive dal server ed è un metodo "safe" (non può cambiare la risorsa). Oltre alla richiesta OPTIONS vengono mandate altre due richieste (linee 10 e 11):
Access-Control-Request-Method: POST Access-Control-Request-Headers: X-PINGOTHER, Content-Type
L'header {{HTTPHeader("Access-Control-Request-Method")}} notifica il server che la richiesta vera e propria verrà mandata con un metodo POST
. L'header {{HTTPHeader("Access-Control-Request-Headers")}} dice al server che verrà mandata con gli header personalizzati X-PINGOTHER
e Content-Type. Ora il server può determinare se vuole accettare una richiesta in queste circostanze.
Le linee 14-26 sono la risposta e indicano che il metodo richiesta (POST
) e gli headers (X-PINGOTHER
) sono accettabili. In particolare, vediamo le linee 17-20:
Access-Control-Allow-Origin: http://foo.example Access-Control-Allow-Methods: POST, GET Access-Control-Allow-Headers: X-PINGOTHER, Content-Type Access-Control-Max-Age: 86400
Il server risponde con Access-Control-Allow-Methods
e dice che POST
e GET
possono essere usati per accedere alla risorsa. Questo header è simile a {{HTTPHeader("Allow")}} ma è usato solo nel contesto del controllo d'accesso.
The server also sends Access-Control-Allow-Headers
with a value of "X-PINGOTHER, Content-Type
", confirming that these are permitted headers to be used with the actual request. Like Access-Control-Allow-Methods
, Access-Control-Allow-Headers
is a comma separated list of acceptable headers.
Finally, {{HTTPHeader("Access-Control-Max-Age")}} gives the value in seconds for how long the response to the preflight request can be cached for without sending another preflight request. In this case, 86400 seconds is 24 hours. Note that each browser has a maximum internal value that takes precedence when the Access-Control-Max-Age
is greater.
Not all browsers currently support following redirects after a preflighted request. If a redirect occurs after a preflighted request, some browsers currently will report an error message such as the following.
The request was redirected to 'https://example.com/foo', which is disallowed for cross-origin requests that require preflight
Request requires preflight, which is disallowed to follow cross-origin redirect
The CORS protocol originally required that behavior but was subsequently changed to no longer require it. However, not all browsers have implemented the change, and so still exhibit the behavior that was originally required.
So until all browsers catch up with the spec, you may be able to work around this limitation by doing one or both of the following:
But if it’s not possible to make those changes, then another way that may be possible is to this:
Response.url
or XMLHttpRequest.responseURL
in the first step.However, if the request is one that triggers a preflight due to the presence of the Authorization
header in the request, you won’t be able to work around the limitation using the steps above. And you won’t be able to work around it at all unless you have control over the server the request is being made to.
The most interesting capability exposed by both {{domxref("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 {{domxref("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 {{domxref("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 {{HTTPHeader("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 {{HTTPHeader("Access-Control-Allow-Credentials")}}: true
(line 19) the response would be ignored and not made available to web content.
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.
Note that cookies set in CORS responses are subject to normal third-party cookie policies. In the example above, the page is loaded from foo.example
, but the cookie on line 22 is sent by bar.other
, and would thus not be saved if the user has configured their browser to reject all third-party cookies.
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.
A returned resource may have one {{HTTPHeader("Access-Control-Allow-Origin")}} header, with the following syntax:
Access-Control-Allow-Origin: <origin> | *
Access-Control-Allow-Origin
specifies either a single origin, which tells browsers to allow that origin to access the resource; or else — for requests without credentials — the "*
" wildcard, to tell browsers to allow any origin to access the resource.
For example, to allow code from the origin http://mozilla.org
to access the resource, you can specify:
Access-Control-Allow-Origin: http://mozilla.org
If the server specifies a single origin rather than the "*
" wildcard, then the server should also include Origin
in the {{HTTPHeader("Vary")}} response header — to indicate to clients that server responses will differ based on the value of the {{HTTPHeader("Origin")}} request header.
The {{HTTPHeader("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.
The {{HTTPHeader("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.
The {{HTTPHeader("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.
The {{HTTPHeader("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.
The {{HTTPHeader("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>]*
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 {{domxref("XMLHttpRequest")}} capability do not have to set any cross-origin sharing request headers programmatically.
The {{HTTPHeader("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.
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 {{HTTPHeader("Origin")}} header is always sent.
The {{HTTPHeader("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.
The {{HTTPHeader("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.
Specification | Status | Comment |
---|---|---|
{{SpecName('Fetch', '#cors-protocol', 'CORS')}} | {{Spec2('Fetch')}} | New definition; supplants W3C CORS specification. |
The compatibility table in this page is generated from structured data. If you'd like to contribute to the data, please check out https://github.com/mdn/browser-compat-data and send us a pull request.
{{Compat("http.headers.Access-Control-Allow-Origin")}}
XDomainRequest
object, but have a full implementation in IE 10.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()
.XMLHttpRequest
and Cross-Origin Resource Sharing