Access-Control-Allow-Origin Multiple Origin Domains?

991,610

Solution 1

Sounds like the recommended way to do it is to have your server read the Origin header from the client, compare that to the list of domains you would like to allow, and if it matches, echo the value of the Origin header back to the client as the Access-Control-Allow-Origin header in the response.

With .htaccess you can do it like this:

# ----------------------------------------------------------------------
# Allow loading of external fonts
# ----------------------------------------------------------------------
<FilesMatch "\.(ttf|otf|eot|woff|woff2)$">
    <IfModule mod_headers.c>
        SetEnvIf Origin "http(s)?://(www\.)?(google.com|staging.google.com|development.google.com|otherdomain.example|dev02.otherdomain.example)$" AccessControlAllowOrigin=$0
        Header add Access-Control-Allow-Origin %{AccessControlAllowOrigin}e env=AccessControlAllowOrigin
        Header merge Vary Origin
    </IfModule>
</FilesMatch>

Solution 2

Another solution I'm using in PHP:

$http_origin = $_SERVER['HTTP_ORIGIN'];

if ($http_origin == "http://www.domain1.com" || $http_origin == "http://www.domain2.com" || $http_origin == "http://www.domain3.com")
{  
    header("Access-Control-Allow-Origin: $http_origin");
}

Solution 3

This worked for me:

SetEnvIf Origin "^http(s)?://(.+\.)?(domain\.example|domain2\.example)$" origin_is=$0 
Header always set Access-Control-Allow-Origin %{origin_is}e env=origin_is

When put in .htaccess, it will work for sure.

Solution 4

I had the same problem with woff-fonts, multiple subdomains had to have access. To allow subdomains I added something like this to my httpd.conf:

SetEnvIf Origin "^(.*\.example\.com)$" ORIGIN_SUB_DOMAIN=$1
<FilesMatch "\.woff$">
    Header set Access-Control-Allow-Origin "%{ORIGIN_SUB_DOMAIN}e" env=ORIGIN_SUB_DOMAIN
</FilesMatch>

For multiple domains you could just change the regex in SetEnvIf.

Solution 5

Here's how to echo the Origin header back if it matches your domain with Nginx, this is useful if you want to serve a font multiple sub-domains:

location /fonts {
    # this will echo back the origin header
    if ($http_origin ~ "example.org$") {
        add_header "Access-Control-Allow-Origin" $http_origin;
    }
}
Share:
991,610
Thomas J Bradley
Author by

Thomas J Bradley

Professor and developer of the Open Web from Ottawa, Canada

Updated on July 08, 2022

Comments

  • Thomas J Bradley
    Thomas J Bradley almost 2 years

    Is there a way to allow multiple cross-domains using the Access-Control-Allow-Origin header?

    I'm aware of the *, but it is too open. I really want to allow just a couple domains.

    As an example, something like this:

    Access-Control-Allow-Origin: http://domain1.example, http://domain2.example
    

    I have tried the above code but it does not seem to work in Firefox.

    Is it possible to specify multiple domains or am I stuck with just one?

    • sam
      sam over 10 years
    • Daniel W.
      Daniel W. about 10 years
      Using the most recent Firefox, neither comma seperated, nor space seperated domains did work. Matching against a list of domains and putting a single host in the headers is still better security and does work properly.
    • Alex W
      Alex W about 9 years
      If you're struggling with this for HTTPS, I found a solution.
    • The Red Pea
      The Red Pea over 6 years
      @sam or "*" ? shared based by returning the value of the Origin request header, "*", or "null"
    • klues
      klues over 5 years
      important note: allowing only cretain domains in the Access-Control-Allow-Origin header does not mean that other domains cannot trigger a method on this endpoint (e.g. REST API method). It just means that disallowed origins cannot use the result in javascript (browser ensures this). For restricting access to an endpoint for specific domains use a server-side request filter that e.g. returns HTTP 401 for disallowed domains.
    • Null
      Null almost 5 years
      You should always append Vary: Origin header when you want to use multiple URLs, see: fetch.spec.whatwg.org/#cors-protocol-and-http-caches
  • pwes
    pwes over 13 years
    The trick looks promising, but it doesn't work in FF 3.6.13. What I observe is that two headers with the same name are joined into one, with values separated with a comma -- and it doesn't work, as OP posted. I observed the headers in LiveHTTPHeaders and FireBug.
  • B T
    B T about 13 years
    See, when I did it, I did "Header set ..." rather than "Header add ..." - seems to work for me. Firefox 3.6.16
  • Sairam
    Sairam over 11 years
    This is not allowed and does not work in FF - bugzilla.mozilla.org/show_bug.cgi?id=671608
  • Jack James
    Jack James about 11 years
    there's a variation on this which seems to work: stackoverflow.com/questions/9466496/…
  • ErJab
    ErJab almost 11 years
    Just spent two hours trying to fix an issue related to CORS and it turns out that it was because of multiple Access-Control-Allow-Origin headers. I removed the multiple Access-Control-Allow-Origin headers and it started working. So this is not the right answer despite the number of votes. Use this method instead to support multiple domains: stackoverflow.com/a/1850482/123545
  • Danger
    Danger about 10 years
    You will in fact get an error message in the log from the latest Chrome browser as of now, telling you that it's ignoring the Access-Control-Allow-Origin header because there are multiple values.
  • AlexChaffee
    AlexChaffee almost 10 years
    Nope. From developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_COR‌​S : "A returned resource may have one Access-Control-Allow-Origin header" .. and from w3.org/TR/cors/#access-control-allow-origin-response-header : "Rather than allowing a space-separated list of origins, it is either a single origin or the string "null"" (first I've heard of "null" here btw)
  • Lior
    Lior over 9 years
    The specs clearly say that multiple values will cause the CORS algorithm to fails. So this isn't correct.
  • Radley Sustaire
    Radley Sustaire over 9 years
    Also confirming this is incorrect. Using this to serve CSS to four domains, I receive an error in Chrome's log "[...] header contains multiple values 'aaa.com, bbb.com', but only one is allowed". It does not matter if you define it as one header, or multiple, or using add vs. set. It just doesn't work.
  • Mike Kormendy
    Mike Kormendy about 9 years
    I like this option and combined/modified it with the implementation that @George has. Sometimes servers don't have a2enmod available, so all you have to do is check your main httpd.conf to see if the line: LoadModule headers_module modules/mod_headers.so is uncommented.
  • spazm
    spazm about 9 years
    'serving ads over ssl' links to the spec w3.org/TR/cors/#access-control-allow-origin-response-header which adds a note, "In practice the origin-list-or-null production is more constrained. Rather than allowing a space-separated list of origins, it is either a single origin or the string "null".
  • indiv
    indiv about 9 years
    My origin had a port number, so I modified the regular expression to include that: ^http(s)?://(.+\.)?example\.com(:\d+)?$
  • Bob Aman
    Bob Aman about 9 years
    While it's important to note that detail, when a specification says "In practice", it doesn't mean that it's only valid to do it that way. It means that if you do it that way, you may run into problems because the majority of implementors either implement the spec incorrectly or incompletely. The specification does allow for a space-separated list of origins, which you can see here in the EBNF under origin-list: tools.ietf.org/html/rfc6454#section-7.1
  • Tom
    Tom about 4 years
    Access-Control-Allow-Credentials: true is not allowed with wildcard Access-Control-Allow-Origin: *. Set a specific <origin> instead.
  • timhc22
    timhc22 about 4 years
    @Tom, yea, not sure why that was in there, I can't remember, but I might have copied it from the defaults that were added on AWS? Thanks for pointing that out though.
  • MrWhite
    MrWhite over 3 years
    Should probably check that $request_headers['Origin']; exists, otherwise any direct requests are going to trigger an E_NOTICE.
  • Ben Winding
    Ben Winding about 3 years
    How would you add wildcard subdomains like: *.example.com or wildcard ports like: localhost:*
  • Ben Winding
    Ben Winding about 3 years
    For anyone wondering you can do (.+\.google.com) instead of (google.com|staging.google.com)
  • Almenon
    Almenon about 3 years
  • Ahmad Vaqas Khan
    Ahmad Vaqas Khan about 3 years
    Great. Helped me.
  • chichilatte
    chichilatte over 2 years
    Handy to have an example for multiple domains: ^(https?:\/\/localhost:\d+)$|^(https?:\/\/.+\.yourdomain\.co‌​m)$ Here's it in action... regex101.com/r/GZHTLB/1 It's crazy gobbledegook but that regex101 site helps decipher it all.
  • Héctor
    Héctor over 2 years
    How would this behave if there is no match? Which would be the output of Access-Control-Allow-Origin?
  • jub0bs
    jub0bs over 2 years
    That regex is not well designed; in particular, insecure origins (using the http scheme) shouldn't be allowed, and DNS label separators should be escaped (\. instead of .); otherwise, an attacker could for instance buy the developmentzgoogle.com domain and mount cross-origin attacks from there.
  • CodeChari
    CodeChari over 2 years
    HTTP_ORIGIN is not reliable, see stackoverflow.com/questions/41231116/…
  • iWasCloud
    iWasCloud about 2 years
    DO not use this in production, its not safe.
  • iWasCloud
    iWasCloud about 2 years
    DO not use this in production, its not safe.
  • suddjian
    suddjian almost 2 years
    any . in the domain needs to be escaped, otherwise it matches any character. Also, you can have just one if statement instead of using a variable