mozilla

Revision 26100 of HTTP access control (CORS)

  • Revision slug: HTTP_access_control
  • Revision title: HTTP access control
  • Revision id: 26100
  • Created:
  • Creator: RobinEgg
  • Is current revision? No
  • Comment 4289 words added

Revision Content

{{ fx_minversion_header("3") }}

クロスサイト HTTP リクエスト とは、要求を出すリソースが存在するドメインとは異なるドメインのリソースに対して HTTP リクエストを行うことを指します。例えば、ドメイン A (http://domaina.example) にて読み込まれた HTML ウェブページなどから、 img タグ (<img src="http://domainb.foo/image.jpg" />)を用いてドメイン B (http://domainb.foo) 上の画像に対する HTTP リクエストが発行される、という状況を指します。このような状況は今日の web 上では非常にありふれたことであり、数多くの CSS スタイルシートや画像、スクリプトなどの外部リソースがこのようなクロスサイト HTTP リクエストを用いて読み込まれています。

通常、スクリプトによって開始されるクロスサイト HTTP リクエストについては、セキュリティ上の理由から、よく知られた制限が加えられます。例えば、 Firefox 3.5 以前では、 XMLHttpRequest オブジェクトにより発行された HTTP リクエストは 同一生成元ポリシー(same-origin policy)  の制約を受けます。つまり、 XMLHttpRequest を使用した web アプリケーションは自身が読み込まれたドメインとの間でのみ HTTP リクエストを発行でき、他のドメイン上のリソースを読み込むことはできない、ということです。よりよく、より安全な web アプリケーションのマッシュアップを作成するべく、開発者たちは  XMLHttpRequest におけるクロスサイト・リクエストなどの機能を安全に進化させることを望んできました。

W3CWeb Applications Working Group が、新たな Access Control for Cross-Site Requests (クロスサイト・リクエストのためのアクセス制御) という提案を行いました。これは、 web サーバーがサイトを跨ぐアクセスを制御する方法を規定することで、サイト間での安全な通信を保証するというものです。特筆すべき点として、この提案は XMLHttpRequest のような API コンテナを緩衝地帯として用いることで、 Firefox 3.5 以上において同一ドメイン制限を超えることが許容できたということです。この文書において書かれている情報は、 web 管理者、サーバー開発者、web 開発者の方々が興味を抱くようなものでしょう。サーバーサイドでのプログラムについては、サーバー側から見たアクセス制御のページで PHP の例示コードととともに議論されていますので、目を通してみてください。

within the W3C has proposed the new Access Control for Cross-Site Requests recommendation, which provides a way for web servers to support cross-site access controls, which enable secure cross-site data transfers.  Of particular note is that this specification is used within an API container such as XMLHttpRequest as a mitigation mechanism, allowing the crossing of the same-domain restriction in Firefox 3.5 and beyond.  The information in this article is of interest to web administrators, server developers and web developers.  Another article for server programmers discussing access control from a server perspective (with PHP code snippets) is supplementary reading.  On the client, Firefox handles the components of access control, including headers and policy enforcement.  The introduction of this new capability, however, does mean that servers have to handle new headers, and send resources back with new headers.

This access control standard is supported by Firefox 3.5 and later, and is used to enable cross-site HTTP requests for:

This article is a general discussion of Access Control, and includes a discussion of the HTTP headers as implemented in Firefox 3.5. 

Overview

The Access Control standard works by adding new HTTP headers that allow servers to describe the set of origins that are permitted to read that information using a web browser.  Firefox supports these headers and enforces the restrictions they establish.  Additionally, for HTTP request methods that can cause side-effects on user data (in particular, for HTTP methods other than GET, or for POST usage with certain MIME types), the specification mandates that browsers "preflight" the request, soliciting supported methods from the server with an HTTP OPTIONS request header, and then, upon "approval" from the server, sending the actual request with the actual HTTP request method.  Servers can also notify clients whether "credentials" (including Cookies and HTTP Authentication data) should be sent with requests.

Subsequent sections discuss scenarios, as well as a breakdown of the HTTP headers used. 

Examples of access control scenarios

Here, we present three scenarios that are illustrative of how Access Control works.  All of these examples use the XMLHttpRequest object, which can be used to make cross-site invocations in Firefox 3.5 and beyond.

The JavaScript snippets included in these sections (and running instances of the server-code that correctly handles these cross-site requests) can be found "in action" here, and will work in browsers that support cross-site XMLHttpRequest.  A discussion of Access Control from a server perspective (including PHP code snippets) can be found here.

Simple requests

A simple cross-site request is one that:

  • Only uses GET or POST.  If POST is used to send data to the server, the Content-Type of the data sent to the server with the HTTP POST request is one of application/x-www-form-urlencoded, multipart/form-data, or text/plain.
  • Does not set custom headers with the HTTP Request (such as X-Modified, etc.)

For example, suppose web content on domain http://foo.example wishes to invoke content on domain http://bar.other.  Code of this sort might be used within JavaScript deployed on 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(); 
        }

Let us look at what the browser will send the server in this case, and let's see how the server responds:

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
Keep-Alive: 300
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]

 Lines 1 - 11 are headers sent by Firefox 3.5.  Note that the main HTTP request header of note here is the Origin: header on line 11 above, which shows that the invocation is coming from content on the the domain http://foo.example.

Lines 14 - 23 show the HTTP response from the server on domain http://bar.other.  In response, the server sends back an Access-Control-Allow-Origin: header, shown above in line 17.  The use of the Origin: header and of Access-Control-Allow-Origin: show the access control protocol in its simplest use.  In this case, the server responds with a Access-Control-Allow-Origin: * which means that the resource can be accessed by any domain in a cross-site manner.  If the resource owners at http://bar.other wished to restrict access to the resource to be only from http://foo.example, they would send back:

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

Note that now, no other domain other than http://foo.example (identified by the ORIGIN: header in the request, as in line 11 above) can access the resource on in a cross-site manner.  The Access-Control-Allow-Origin header should contain a comma separated list of acceptable domains. 

Preflighted requests

Unlike simple requests (discussed above), "preflighted" requests first send an HTTP OPTIONS request header to the resource on the other domain, in order to determine whether the actual request is safe to send.  Cross-site requests are preflighted like this since they may have implications to user data.  In particular, a request is preflighted if:

  • It uses methods other than GET or POST.  Also, if POST is used to send request data with a Content-Type other than application/x-www-form-urlencoded, multipart/form-data, or text/plain, e.g. if the POST request sends an XML payload to the server using application/xml or text/xml, then the request is preflighted.
  • It sets custom headers in the request (e.g. the request uses a header such as X-PINGOTHER)

An example of this kind of invocation might be:

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

......

In the example above, line 3 creates an XML body to send with the POST request in line 8.  Also, on line 9, a "customized" (non-standard) HTTP request header is set (X-PINGOTHER: pingpong).  Such headers are not part of the HTTP/1.1 protocol, but are generally useful to web applications.  Since the request (POST) uses a Content-Type of application/xml, and since a custom header is set, this request is preflighted.

Let's take a look at the full exchange between client and server:

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
Keep-Alive: 300
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
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
Keep-Alive: 300
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
Content-Encoding: gzip
Content-Length: 235
Keep-Alive: timeout=2, max=99
Connection: Keep-Alive
Content-Type: text/plain

[Some GZIP'd payload]

Lines 1 - 12 above represent the preflight request with the OPTIONS header.  Firefox 3.1 determines that it needs to send this based on the request parameters that the JavaScript code snippet above was using, so that the server can respond whether it is acceptable to send the request with the actual request parameters.  OPTIONS is an HTTP/1.1 header that is used to determine further information from servers, and is an idempotent method, meaning that it can't be used to change the resource.  Note that along with the OPTIONS header, two other request headers are sent (lines 11 and 12 respectively):

Access-Control-Request-Method: POST
Access-Control-Request-Headers: X-PINGOTHER

The Access-Control-Request-Method header notifies the server as part of a preflight request that when the actual request is sent, it will be sent with a POST request method. The Access-Control-Request-Headers header notifies the server that when the actual request is sent, it will be sent with an X-PINGOTHER custom header.  The server now has an opportunity to determine whether it wishes to accept a request under these circumstances.

Lines 15 - 27 above are the response that the server sends back indicating that the request method (POST) and request headers (X-PINGOTHER) are acceptable.  In particular, let's look at lines 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

The server responds with Access-Control-Allow-Methods and says that POST, GET, and OPTIONS are viable methods to query the resource in question.  Note that this header is similar to the HTTP/1.1 Allow: response header, but used strictly within the context of access control.  The server also sends Access-Control-Allow-Headers with a value of X-PINGOTHER, confirming that this is a permitted header 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, 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, 1728000 seconds is 20 days.

Requests with credentials

The most interesting capability exposed by both XMLHttpRequest and Access Control in Firefox 3.5 is the ability to make "credentialed" requests that are cognizant of HTTP Cookies and HTTP Authentication information.  By default, in cross-site XMLHttpRequest invocations, Firefox 3.5 and beyond will not send credentials.  A specific flag has to be set on the XMLHttpRequest object 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 8 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 Firefox 3.5 (and greater) 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
Keep-Alive: 300
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
Content-Encoding: gzip
Content-Length: 106
Keep-Alive: timeout=2, max=100
Connection: Keep-Alive
Content-Type: text/plain


[text/plain payload]

Although line 12 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 20) the response would be ignored and not made available to web content.  Important note: when responding to a credentialed request,  server must specify a domain, and cannot use wild carding.  The above example would fail if the header was wildcarded as: Access-Control-Allow-Origin: *.  Since the Access-Control-Allow-Origin explicitly mentions http://foo.example, the credential-cognizant content is returned to the invoking web content.  Note that in line 23, a further cookie is set.

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

The HTTP response headers

This section lists the HTTP response headers that servers send back for access control requests as defined by the access control 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.com to access the resource, you can specify:

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

Access-Control-Max-Age

This 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

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 | false

Credentialed requests are discussed above.

Access-Control-Allow-Methods

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 by Firefox 3.5 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

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>]*

The HTTP request headers

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

Origin

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

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

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.

See also

 

Revision Source

<p>{{ fx_minversion_header("3") }}</p>
<p><strong>クロスサイト HTTP リクエスト</strong> とは、要求を出すリソースが存在するドメインとは<em>異なるドメインの</em>リソースに対して HTTP リクエストを行うことを指します。例えば、ドメイン A (<code class="plain">http://domaina.example</code>) にて読み込まれた HTML ウェブページなどから、 <code>img</code> タグ (<code class="plain">&lt;img src="http://domainb.foo/image.jpg" /&gt;</code>)を用いてドメイン B (<code class="plain">http://domainb.foo</code>) 上の画像に対する HTTP リクエストが発行される、という状況を指します。このような状況は今日の web 上では非常にありふれたことであり、数多くの CSS スタイルシートや画像、スクリプトなどの外部リソースがこのようなクロスサイト HTTP リクエストを用いて読み込まれています。</p>
<p>通常、スクリプトによって開始されるクロスサイト HTTP リクエストについては、セキュリティ上の理由から、よく知られた制限が加えられます。例えば、 Firefox 3.5 以前では、 <a class="internal" href="/Ja/XMLHttpRequest" title="Ja/XMLHttpRequest"><code>XMLHttpRequest</code></a> オブジェクトにより発行された HTTP リクエストは <a class="internal" href="/Ja/Same_origin_policy_for_JavaScript" title="Ja/Same origin policy for JavaScript">同一生成元ポリシー(same-origin policy)</a>  の制約を受けます。つまり、 <a class="internal" href="/Ja/XMLHttpRequest" title="Ja/XMLHttpRequest"><code>XMLHttpRequest</code></a> を使用した web アプリケーションは自身が読み込まれたドメインとの間で<em>のみ</em> HTTP リクエストを発行でき、他のドメイン上のリソースを読み込むことはできない、ということです。よりよく、より安全な web アプリケーションのマッシュアップを作成するべく、開発者たちは  <a class="internal" href="/Ja/XMLHttpRequest" title="Ja/XMLHttpRequest"><code>XMLHttpRequest</code></a> におけるクロスサイト・リクエストなどの機能を安全に進化させることを望んできました。</p>
<p><a class="external" href="http://www.w3.org/" title="http://www.w3.org/">W3C</a> の <a class="external" href="http://www.w3.org/2008/webapps/" title="http://www.w3.org/2008/webapps/">Web Applications Working Group</a> が、新たな <a class="external" href="http://dev.w3.org/2006/waf/access-control/" title="http://dev.w3.org/2006/waf/access-control/">Access Control for Cross-Site Requests (クロスサイト・リクエストのためのアクセス制御)</a> という提案を行いました。これは、 web サーバーがサイトを跨ぐアクセスを制御する方法を規定することで、サイト間での安全な通信を保証するというものです。特筆すべき点として、この提案は <a class="internal" href="/Ja/XMLHttpRequest" title="Ja/XMLHttpRequest"><code>XMLHttpRequest</code></a> のような <em>API コンテナ</em>を緩衝地帯として用いることで、 Firefox 3.5 以上において同一ドメイン制限を超えることが許容できたということです。この文書において書かれている情報は、 web 管理者、サーバー開発者、web 開発者の方々が興味を抱くようなものでしょう。サーバーサイドでのプログラムについては、<a class="internal" href="/Ja/Server-Side_Access_Control" title="Ja/Server-Side Access Control">サーバー側から見たアクセス制御</a>のページで PHP の例示コードととともに議論されていますので、目を通してみてください。</p>
<p>within the <a class="external" href="http://www.w3.org/" title="http://www.w3.org/">W3C</a> has proposed the new <a class="external" href="http://dev.w3.org/2006/waf/access-control/" title="http://dev.w3.org/2006/waf/access-control/">Access Control for Cross-Site Requests</a> recommendation, which provides a way for web servers to support cross-site access controls, which enable secure cross-site data transfers.  Of particular note is that this specification is used within an <em>API container</em> such as <code><a class="internal" href="/en/XMLHttpRequest" title="En/XMLHttpRequest">XMLHttpRequest</a></code> as a mitigation mechanism, allowing the crossing of the same-domain restriction in Firefox 3.5 and beyond.  The information in this article is of interest to web administrators, server developers and web developers.  Another article for server programmers discussing <a class="internal" href="/En/Server-Side_Access_Control" title="En/Server-Side Access Control">access control from a server perspective (with PHP code snippets)</a> is supplementary reading.  On the client, Firefox handles the components of access control, including headers and policy enforcement.  The introduction of this new capability, however, does mean that servers have to handle new headers, and send resources back with new headers.</p>
<p>This <a class="external" href="http://dev.w3.org/2006/waf/access-control/" title="http://dev.w3.org/2006/waf/access-control/">access control standard</a> is supported by Firefox 3.5 and later, and is used to enable cross-site HTTP requests for:</p>
<ul> <li>Invocations of the <a class="internal" href="/en/XMLHttpRequest" title="En/XMLHttpRequest"><code>XMLHttpRequest</code></a> API in a cross-site manner, as discussed above.  This is implemented in Firefox 3.5.</li> <li>Web Fonts (for cross-domain font usage in <code>@font-face</code> within CSS), <a class="external" href="http://www.webfonts.info/wiki/index.php?title=%40font-face_support_in_Firefox" title="http://www.webfonts.info/wiki/index.php?title=@font-face_support_in_Firefox">so that servers can deploy TrueType fonts that can only be cross-site loaded and used by web sites that are permitted to do so.</a>  This is implemented in Firefox 3.5.</li>
</ul>
<p>This article is a general discussion of Access Control, and includes a discussion of the HTTP headers as implemented in Firefox 3.5. </p>
<h2>Overview</h2>
<p>The Access Control standard works by adding new HTTP headers that allow servers to describe the set of origins that are permitted to read that information using a web browser.  Firefox supports these headers and enforces the restrictions they establish.  Additionally, for HTTP request methods that can cause side-effects on user data (in particular, for HTTP methods other than <code>GET</code>, or for <code>POST</code> usage with certain MIME types), the specification mandates that browsers "preflight" the request, soliciting supported methods from the server with an HTTP <code>OPTIONS</code> request header, and then, upon "approval" from the server, sending the actual request with the actual HTTP request method.  Servers can also notify clients whether "credentials" (including Cookies and HTTP Authentication data) should be sent with requests.</p>
<p>Subsequent sections discuss scenarios, as well as a breakdown of the HTTP headers used. </p>
<h2>Examples of access control scenarios</h2>
<p>Here, we present three scenarios that are illustrative of how Access Control works.  All of these examples use the <code><a class="internal" href="/en/XMLHttpRequest" title="En/XMLHttpRequest">XMLHttpRequest</a></code> object, which can be used to make cross-site invocations in Firefox 3.5 and beyond.</p>
<p>The JavaScript snippets included in these sections (and running instances of the server-code that correctly handles these cross-site requests) <a class="external" href="http://arunranga.com/examples/access-control/" title="http://arunranga.com/examples/access-control/">can be found "in action" here</a>, and will work in browsers that support cross-site <a class="internal" href="/en/XMLHttpRequest" title="En/XMLHttpRequest"><code>XMLHttpRequest</code></a>.  A discussion of Access Control from a <a class="internal" href="/En/Server-Side_Access_Control" title="En/Server-Side Access Control">server perspective (including PHP code snippets) can be found here</a>.</p>
<h3>Simple requests</h3>
<p>A simple cross-site request is one that:</p>
<ul> <li>Only uses GET or POST.  If POST is used to send data to the server, the Content-Type of the data sent to the server with the HTTP POST request is one of <code>application/x-www-form-urlencoded</code>, <code>multipart/form-data</code>, or <code>text/plain.</code></li> <li>Does not set custom headers with the HTTP Request (such as <code>X-Modified</code>, etc.)</li>
</ul>
<p>For example, suppose web content on domain <code class="plain">http://foo.example</code> wishes to invoke content on domain <code class="plain">http://bar.other</code>.  Code of this sort might be used within JavaScript deployed on foo.example:</p>
<pre class="brush: js" id="line1">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(); 
        }
</pre>
<p>Let us look at what the browser will send the server in this case, and let's see how the server responds:</p>
<pre class="brush: shell">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
Keep-Alive: 300
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]
</pre>
<p> Lines 1 - 11 are headers sent by Firefox 3.5.  Note that the main HTTP request header of note here is the <code>Origin:</code> header on line 11 above, which shows that the invocation is coming from content on the the domain <code class="plain">http://foo.example</code>.</p>
<p>Lines 14 - 23 show the HTTP response from the server on domain <code class="plain">http://bar.other</code>.  In response, the server sends back an <code>Access-Control-Allow-Origin:</code> header, shown above in line 17.  The use of the <code>Origin:</code> header and of <code>Access-Control-Allow-Origin:</code> show the access control protocol in its simplest use.  In this case, the server responds with a <code>Access-Control-Allow-Origin: *</code> which means that the resource can be accessed by <strong>any</strong> domain in a cross-site manner.  If the resource owners at <code class="plain">http://bar.other</code> wished to restrict access to the resource to be only from <code class="plain">http://foo.example</code>, they would send back:</p>
<p><code class="plain">Access-Control-Allow-Origin: http://foo.example</code></p>
<p>Note that now, no other domain other than <code class="plain">http://foo.example</code> (identified by the ORIGIN: header in the request, as in line 11 above) can access the resource on in a cross-site manner.  The <code>Access-Control-Allow-Origin</code> header should contain a comma separated list of acceptable domains. </p>
<h3>Preflighted requests</h3>
<p>Unlike simple requests (discussed above), "preflighted" requests first send an HTTP <code>OPTIONS</code> request header to the resource on the other domain, in order to determine whether the actual request is safe to send.  Cross-site requests are preflighted like this since they may have implications to user data.  In particular, a request is preflighted if:</p>
<ul> <li>It uses methods <strong>other</strong> than <code>GET</code> or <code>POST</code>.  Also, if <code>POST</code> is used to send request data with a Content-Type <strong>other</strong> than <code>application/x-www-form-urlencoded</code>, <code>multipart/form-data</code>, or <code>text/plain</code>, e.g. if the <code>POST</code> request sends an XML payload to the server using <code>application/xml</code> or <code>text/xml</code>, then the request <strong>is</strong> preflighted.</li> <li>It sets custom headers in the request (e.g. the request uses a header such as <code>X-PINGOTHER</code>)</li>
</ul>
<p>An example of this kind of invocation might be:</p>
<pre class="brush: js" id="line1">var invocation = new XMLHttpRequest();
var url = 'http://bar.other/resources/post-here/';
var body = '&lt;?xml version="1.0"?&gt;&lt;person&gt;&lt;name&gt;Arun&lt;/name&gt;&lt;/person&gt;';
    
    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); 
        }

......
</pre>
<p>In the example above, line 3 creates an XML body to send with the <code>POST</code> request in line 8.  Also, on line 9, a "customized" (non-standard) HTTP request header is set (<code>X-PINGOTHER: pingpong</code>).  Such headers are not part of the HTTP/1.1 protocol, but are generally useful to web applications.  Since the request (<code>POST</code>) uses a Content-Type of <code>application/xml</code>, and since a custom header is set, this request is preflighted.</p>
<p>Let's take a look at the full exchange between client and server:</p>
<pre class="brush: shell">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
Keep-Alive: 300
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
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
Keep-Alive: 300
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

&lt;?xml version="1.0"?&gt;&lt;person&gt;&lt;name&gt;Arun&lt;/name&gt;&lt;/person&gt;


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
Content-Encoding: gzip
Content-Length: 235
Keep-Alive: timeout=2, max=99
Connection: Keep-Alive
Content-Type: text/plain

[Some GZIP'd payload]
</pre>
<p>Lines 1 - 12 above represent the preflight request with the <code>OPTIONS</code> header.  Firefox 3.1 determines that it needs to send this based on the request parameters that the JavaScript code snippet above was using, so that the server can respond whether it is acceptable to send the request with the actual request parameters.  OPTIONS is an HTTP/1.1 header that is used to determine further information from servers, and is an <strong>idempotent</strong> method, meaning that it can't be used to change the resource.  Note that along with the OPTIONS header, two other request headers are sent (lines 11 and 12 respectively):</p>
<pre>Access-Control-Request-Method: POST
Access-Control-Request-Headers: X-PINGOTHER
</pre>
<p>The <code>Access-Control-Request-Method</code> header notifies the server as part of a preflight request that when the actual request is sent, it will be sent with a <code>POST</code> request method. The <code>Access-Control-Request-Headers</code> header notifies the server that when the actual request is sent, it will be sent with an <code>X-PINGOTHER</code> custom header.  The server now has an opportunity to determine whether it wishes to accept a request under these circumstances.</p>
<p>Lines 15 - 27 above are the response that the server sends back indicating that the request method (<code>POST</code>) and request headers (<code>X-PINGOTHER</code>) are acceptable.  In particular, let's look at lines 18-21:</p>
<pre>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</pre>
<p>The server responds with <code>Access-Control-Allow-Methods</code> and says that <code>POST</code>, <code>GET</code>, and <code>OPTIONS</code> are viable methods to query the resource in question.  Note that this header is similar to the <a class="external" href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.7" title="http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.7">HTTP/1.1 Allow: response header</a>, but used strictly within the context of access control.  The server also sends <code>Access-Control-Allow-Headers</code> with a value of <code>X-PINGOTHER</code>, confirming that this is a permitted header to be used with the actual request.  Like <code>Access-Control-Allow-Methods</code>, <code>Access-Control-Allow-Headers</code> is a comma separated list of acceptable headers.  Finally, <code>Access-Control-Max-Age</code> 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, 1728000 seconds is 20 days.</p>
<h3>Requests with credentials</h3>
<p>The most interesting capability exposed by both <a class="internal" href="/en/XMLHttpRequest" title="En/XMLHttpRequest"><code>XMLHttpRequest</code></a> and Access Control in Firefox 3.5 is the ability to make "credentialed" requests that are cognizant of HTTP Cookies and HTTP Authentication information.  By default, in cross-site <a class="internal" href="/en/XMLHttpRequest" title="En/XMLHttpRequest"><code>XMLHttpRequest</code></a> invocations, Firefox 3.5 and beyond will <strong>not</strong> send credentials.  A specific flag has to be set on the <a class="internal" href="/en/XMLHttpRequest" title="En/XMLHttpRequest"><code>XMLHttpRequest</code></a> object when it is invoked.</p>
<p>In this example, content originally loaded from <code class="plain">http://foo.example</code> makes a simple GET request to a resource on <code class="plain">http://bar.other</code> which sets Cookies.  Content on foo.example might contain JavaScript like this:</p>
<pre class="brush: js" id="line1">    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(); 
        }
</pre>
<p>Line 8 shows the flag on <a class="internal" href="/en/XMLHttpRequest" title="En/XMLHttpRequest"><code>XMLHttpRequest</code></a> that has to be set in order to make the invocation with Cookies, namely the <code>withCredentials</code> boolean value.  By default, the invocation is made without Cookies.  Since this is a simple <code>GET</code> request, it is not preflighted, but Firefox 3.5 (and greater) will <strong>reject</strong> any response that does not have the <code>Access-Control-Allow-Credentials: true</code> header, and <strong>not</strong> make the response available to the invoking web content.</p>
<p>Here is a sample exchange between client and server:</p>
<pre class="brush: shell">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
Keep-Alive: 300
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
Content-Encoding: gzip
Content-Length: 106
Keep-Alive: timeout=2, max=100
Connection: Keep-Alive
Content-Type: text/plain


[text/plain payload]
</pre>
<p>Although line 12 contains the Cookie destined for the content on <code class="plain">http://bar.other</code>, if bar.other did not respond with an <code>Access-Control-Allow-Credentials: true</code> (line 20) the response would be ignored and not made available to web content.  <strong>Important note:</strong> when responding to a credentialed request,  server <strong>must </strong>specify a domain, and cannot use wild carding.  The above example would fail if the header was wildcarded as: <code>Access-Control-Allow-Origin: *</code>.  Since the <code>Access-Control-Allow-Origin</code> explicitly mentions <code class="plain">http://foo.example</code>, the credential-cognizant content is returned to the invoking web content.  Note that in line 23, a further cookie is set.</p>
<p>All of these examples can be <a class="external" href="http://arunranga.com/examples/access-control/" title="http://arunranga.com/examples/access-control/">seen working here</a>.  The next section deals with the actual HTTP headers.</p>
<h2>The HTTP response headers</h2>
<p>This section lists the HTTP response headers that servers send back for access control requests as defined by the access control specification.  The previous section gives an overview of these in action.</p>
<h3>Access-Control-Allow-Origin</h3>
<p>A returned resource may have one <code>Access-Control-Allow-Origin</code> header, with the following syntax:</p>
<pre>Access-Control-Allow-Origin: &lt;origin&gt; | *
</pre>
<p>The <code>origin</code> parameter specifies a URI that may access the resource.  The browser must enforce this.  For requests <strong>without</strong> credentials, the server may specify "*" as a wildcard, thereby allowing any origin to access the resource.</p>
<p>For example, to allow <code class="plain">http://mozilla.com</code> to access the resource, you can specify:</p>
<pre>Access-Control-Allow-Origin: http://mozilla.com</pre>
<h3>Access-Control-Max-Age</h3>
<p>This header indicates how long the results of a preflight request can be cached.  For an example of a preflight request, see the above examples.</p>
<pre>Access-Control-Max-Age: &lt;delta-seconds&gt;
</pre>
<p>The <code>delta-seconds</code> parameter indicates the number of seconds the results can be cached.</p>
<h3>Access-Control-Allow-Credentials</h3>
<p>Indicates whether or not the response to the request can be exposed when the <code>credentials</code> 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 <code>GET</code> 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.</p>
<pre>Access-Control-Allow-Credentials: true | false
</pre>
<p><a class="internal" href="/#Requests_with_Credentials" title="#Requests with Credentials">Credentialed requests</a> are discussed above.</p>
<h3>Access-Control-Allow-Methods</h3>
<p>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 by Firefox 3.5 are discussed above.</p>
<pre>Access-Control-Allow-Methods: &lt;method&gt;[, &lt;method&gt;]*
</pre>
<p>An example of a <a class="internal" href="/#Preflight_Request" title="#Preflight Request">preflight request is given above</a>, including an example which sends this header to the browser.</p>
<h3>Access-Control-Allow-Headers</h3>
<p>Used in response to a <a class="internal" href="/#Preflighted_Request" title="#Preflighted Request">preflight request</a> to indicate which HTTP headers can be used when making the actual request.</p>
<pre>Access-Control-Allow-Headers: &lt;field-name&gt;[, &lt;field-name&gt;]*
</pre>
<h2>The HTTP request headers</h2>
<p>This section lists headers that clients may use when issuing HTTP requests in order to make use of the access control feature.  Note that Firefox 3.5 will set these headers for you when making invocations to servers.  Developers using Firefox's cross-site <a class="internal" href="/en/XMLHttpRequest" title="En/XMLHttpRequest"><code>XMLHttpRequest</code></a> capability do not have to set any access control request headers programmatically.</p>
<h3>Origin</h3>
<p>Indicates the origin of the cross-site access request or preflight request.</p>
<pre>Origin: &lt;origin&gt;
</pre>
<p>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.</p>
<div class="note"><strong>Note:</strong> The <code>origin</code> can be the empty string; this is useful, for example, if the source is a <code>data</code> URL.</div>
<p>Note that in any access control request, the <code>ORIGIN</code> header is <strong>always</strong> sent.</p>
<h3>Access-Control-Request-Method</h3>
<p>Used when issuing a preflight request to let the server know what HTTP method will be used when the actual request is made.</p>
<pre>Access-Control-Request-Method: &lt;method&gt;
</pre>
<p>Examples of this usage can be <a class="internal" href="#Preflighted_requests" title="Preflighted requests">found above.</a> </p>
<h3>Access-Control-Request-Headers</h3>
<p>Used when issuing a preflight request to let the server know what HTTP headers will be used when the actual request is made.</p>
<pre>Access-Control-Request-Headers: &lt;field-name&gt;[, &lt;field-name&gt;]*
</pre>
<p>Examples of this usage can be <a class="internal" href="/#Preflighted_Requests" title="#Preflighted Requests">found above</a>.</p>
<h2>See also</h2>
<ul> <li><a class="external" href="http://arunranga.com/examples/access-control/" title="http://arunranga.com/examples/access-control/">Code Samples Showing <code>XMLHttpRequest</code> and Access Control</a></li> <li><a class="internal" href="/En/Server-Side_Access_Control" title="En/Server-Side Access Control">Access Control From a Server-Side Perspective (PHP, etc.)</a></li> <li><a class="external" href="http://dev.w3.org/2006/waf/access-control/" title="http://dev.w3.org/2006/waf/access-control/">Access Control for Cross-Site Requests specification</a> </li> <li><a class="internal" href="/en/XMLHttpRequest" title="en/XMLHttpRequest"><code>XMLHttpRequest</code></a> </li> <li><a class="external" href="http://crypto.stanford.edu/websec/specs/origin-header/" title="http://crypto.stanford.edu/websec/specs/origin-header/">Further Discussion of the Origin Header</a></li>
</ul>
<p> </p>
Revert to this revision