webdevqa.jp.net

アクセス制御許可起点複数起点ドメイン?

Access-Control-Allow-Originヘッダーを使用して複数のクロスドメインを許可する方法はありますか?

私は*を知っていますが、それはオープンすぎています。私は本当に2つのドメインだけを許可したいです。

例として、このようなもの:

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

私は上記のコードを試してみましたが、Firefoxでは動作しないようです。

複数のドメインを指定することは可能ですか、それとも1つだけを使用しますか。

926

推奨される方法は、サーバーからクライアントからのOriginヘッダーを読み取り、それを許可したいドメインのリストと比較し、一致する場合はOriginヘッダーの値をクライアントにエコーバックすることです応答のAccess-Control-Allow-Originヘッダーとして。

.htaccessを使えば、このようにすることができます:

# ----------------------------------------------------------------------
# Allow loading of external fonts
# ----------------------------------------------------------------------
<FilesMatch "\.(ttf|otf|eot|woff)$">
    <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>
769
yesthatguy

私が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");
}
188
Nikolay Ivanov

これは私のために働いた:

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

.htaccessに入れると、確実に動作します。

101
Jay Dave

私はwoff-フォントについても同じ問題を抱えていました、複数のサブドメインがアクセス権を持っている必要がありました。サブドメインを許可するために、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>

複数のドメインの場合は、SetEnvIfの正規表現を変更するだけで済みます。

85
Staugaard

OriginのヘッダがNginxと一致する場合にOriginのヘッダをエコーバックする方法は次のとおりです。これは、フォントを複数のサブドメインに提供する場合に便利です。

location /fonts {
    # this will echo back the Origin header
    if ($http_Origin ~ "example.org$") {
        add_header "Access-Control-Allow-Origin" $http_Origin;
    }
}
59
mjallday

これは私がAJAXによって要求されているPHPアプリケーションのためにしたことです

$request_headers        = Apache_request_headers();
$http_Origin            = $request_headers['Origin'];
$allowed_http_origins   = array(
                            "http://myDumbDomain.example"   ,
                            "http://anotherDumbDomain.example"  ,
                            "http://localhost"  ,
                          );
if (in_array($http_Origin, $allowed_http_origins)){  
    @header("Access-Control-Allow-Origin: " . $http_Origin);
}

要求元のOriginが私のサーバーで許可されている場合、$http_Originワイルドカードを返す代わりにAccess-Control-Allow-Originヘッダーの値として*自体を返します。

22

注意しなければならない欠点が1つあります。ファイルをCDN(またはスクリプト作成が許可されていない他のサーバー)にアウトソースした直後、またはファイルがプロキシにキャッシュされている場合要求ヘッダーは機能しません。

18
Mark

複数のドメインの場合は、あなたの.htaccessで:

<IfModule mod_headers.c>
    SetEnvIf Origin "http(s)?://(www\.)?(domain1.example|domain2.example)$" AccessControlAllowOrigin=$0$1
    Header add Access-Control-Allow-Origin %{AccessControlAllowOrigin}e env=AccessControlAllowOrigin
    Header set Access-Control-Allow-Credentials true
</IfModule>
16
George

Nginxユーザーが複数のドメインに対してCORSを許可するため。彼の回答は1つのドメインにしか一致しませんが、@ marshallの例が好きです。ドメインとサブドメインのリストを一致させるために、この正規表現はフォントを扱いやすくします。

location ~* \.(?:ttf|ttc|otf|eot|woff|woff2)$ {
   if ( $http_Origin ~* (https?://(.+\.)?(domain1|domain2|domain3)\.(?:me|co|com)$) ) {
      add_header "Access-Control-Allow-Origin" "$http_Origin";
   }
}

これは与えられたドメインのリストと一致する "Access-Control-Allow-Origin"ヘッダだけをエコーし​​ます。

14
Adriano Rosa

URL Rewrite 2.0モジュールがインストールされたIIS 7.5以降の場合は this SO answer

14
Paco Zarate

Yesthatguyからの回答を基にした、Java Webアプリケーションのための解決策は次のとおりです。 

私はJersey REST 1.xを使用しています

Jersey RESTおよびCORSResponseFilterを認識するようにweb.xmlを設定します。

 <!-- Jersey REST config -->
  <servlet>    
    <servlet-name>JAX-RS Servlet</servlet-name>
    <servlet-class>com.Sun.jersey.spi.container.servlet.ServletContainer</servlet-class>
    <init-param> 
        <param-name>com.Sun.jersey.api.json.POJOMappingFeature</param-name>
        <param-value>true</param-value>
    </init-param>
    <init-param>
      <param-name>com.Sun.jersey.spi.container.ContainerResponseFilters</param-name>
      <param-value>com.your.package.CORSResponseFilter</param-value>
    </init-param>   
    <init-param>
        <param-name>com.Sun.jersey.config.property.packages</param-name>
        <param-value>com.your.package</param-value>
    </init-param>        
    <load-on-startup>1</load-on-startup>
  </servlet>
  <servlet-mapping>
    <servlet-name>JAX-RS Servlet</servlet-name>
    <url-pattern>/ws/*</url-pattern>
  </servlet-mapping>

これがCORSResponseFilterのコードです。

import com.Sun.jersey.spi.container.ContainerRequest;
import com.Sun.jersey.spi.container.ContainerResponse;
import com.Sun.jersey.spi.container.ContainerResponseFilter;


public class CORSResponseFilter implements ContainerResponseFilter{

@Override
public ContainerResponse filter(ContainerRequest request,
        ContainerResponse response) {

    String[] allowDomain = {"http://localhost:9000","https://my.domain.example"};
    Set<String> allowedOrigins = new HashSet<String>(Arrays.asList (allowDomain));                  

    String originHeader = request.getHeaderValue("Origin");

    if(allowedOrigins.contains(originHeader)) {
        response.getHttpHeaders().add("Access-Control-Allow-Origin", originHeader);

        response.getHttpHeaders().add("Access-Control-Allow-Headers",
                "Origin, content-type, accept, authorization");
        response.getHttpHeaders().add("Access-Control-Allow-Credentials", "true");
        response.getHttpHeaders().add("Access-Control-Allow-Methods",
                "GET, POST, PUT, DELETE, OPTIONS, HEAD");
    }

    return response;
}

}
11
duvo

上記のように、CDN(Content Delivery Network)を使用している場合は、Access-Control-Allow-Originを一意にし、VaryOriginに設定します。

私のNginx設定の関連部分:

if ($http_Origin ~* (https?://.*\.mydomain.example(:[0-9]+)?)) {
  set $cors "true";
}
if ($cors = "true") {
  add_header 'Access-Control-Allow-Origin' "$http_Origin";
  add_header 'X-Frame-Options' "ALLOW FROM $http_Origin";
  add_header 'Access-Control-Allow-Credentials' 'true';
  add_header 'Vary' 'Origin';
}
9
hernvnc

たぶん私は間違っています、しかし私が見ることができる限りAccess-Control-Allow-Originはパラメータとして"Origin-list"を持っています。

定義 an Origin-listは次のとおりです。

Origin            = "Origin" ":" 1*WSP [ "null" / Origin-list ]
Origin-list       = serialized-Origin *( 1*WSP serialized-Origin )
serialized-Origin = scheme "://" Host [ ":" port ]
                  ; <scheme>, <Host>, <port> productions from RFC3986

そしてこのことから、私は異なる起源が認められており、 スペース区切り であるべきだと主張します。

7
drAlberT

HTTPSを実行しているドメインにこれ​​を設定するのに苦労したので、私は解決策を共有するだろうと考えました。 httpd.confファイルで次のディレクティブを使用しました。

    <FilesMatch "\.(ttf|otf|eot|woff)$">
            SetEnvIf Origin "^http(s)?://(.+\.)?example\.com$" AccessControlAllowOrigin=$0
            Header set Access-Control-Allow-Origin %{AccessControlAllowOrigin}e env=AccessControlAllowOrigin
    </FilesMatch>

example.comをあなたのドメイン名に変更してください。これをhttpd.confファイルの<VirtualHost x.x.x.x:xx>内に追加します。あなたのVirtualHostがポート接尾辞(例えば:80)を持っているならば、このディレクティブはHTTPSに適用されないでしょう、それであなたはまた/ etc/Apache2/sites-available/default-sslに行って同じものを加える必要があるでしょうそのファイルの<VirtualHost _default_:443>セクション内のディレクティブ。

設定ファイルが更新されたら、端末で次のコマンドを実行する必要があります。

a2enmod headers
Sudo service Apache2 reload
5
Alex W

フォントに問題がある場合は、以下を使用してください。

<FilesMatch "\.(ttf|ttc|otf|eot|woff)$">
    <IfModule mod_headers>
        Header set Access-Control-Allow-Origin "*"
    </IfModule>
</FilesMatch>
4
noun

より柔軟な方法は、Apache 2.4の式を使用することです。ドメイン、パス、そして他のほぼすべてのリクエスト変数と照合できます。応答はすべて*ですが、その応答を受け取る唯一の要求者は、とにかく要件を満たすものです。

<IfModule mod_headers.c>
    <If "%{HTTP:Host} =~ /\\bcdndomain\\.example$/i && %{HTTP:Origin} =~ /\\bmaindomain\\.example$/i">
        Header set Access-Control-Allow-Origin "*"
    </If>
</IfModule>
2
Walf

ExpressJSアプリケーションの場合は、次のものを使用できます。

app.use(function(req, res, next) {
    const corsWhitelist = [
        'https://domain1.example',
        'https://domain2.example',
        'https://domain3.example'
    ];
    if (corsWhitelist.indexOf(req.headers.Origin) !== -1) {
        res.header('Access-Control-Allow-Origin', req.headers.Origin);
        res.header('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept');
    }

    next();
});
1
eyecatchUp

これはApache用の拡張オプションで、最新および計画中のフォント定義をいくつか含みます。

<FilesMatch "\.(ttf|otf|eot|woff|woff2|sfnt|svg)$">
    <IfModule mod_headers.c>
        SetEnvIf Origin "^http(s)?://(.+\.)?(domainname1|domainname2|domainname3)\.(?:com|net|org)$" AccessControlAllowOrigin=$0$1$2
        Header add Access-Control-Allow-Origin %{AccessControlAllowOrigin}e env=AccessControlAllowOrigin
        Header set Access-Control-Allow-Credentials true
    </IfModule>
</FilesMatch>
1
Mike Kormendy

.NETアプリケーションのためのかなり簡単なコピー/貼り付けのために、global.asaxファイル内からCORSを有効にするためにこれを書きました。このコードは、現在受け入れられている回答で与えられたアドバイスに従います。リクエストで与えられたOriginの返答がレスポンスに反映されます。これを使用せずに効果的に '*'を達成します。これは、 'withCredentials'属性を 'true'に設定してAJAX XMLHttpRequestを送信する機能など、他の複数のCORS機能を有効にするためです。

void Application_BeginRequest(object sender, EventArgs e)
{
    if (Request.HttpMethod == "OPTIONS")
    {
        Response.AddHeader("Access-Control-Allow-Methods", "GET, POST");
        Response.AddHeader("Access-Control-Allow-Headers", "Content-Type, Accept");
        Response.AddHeader("Access-Control-Max-Age", "1728000");
        Response.End();
    }
    else
    {
        Response.AddHeader("Access-Control-Allow-Credentials", "true");

        if (Request.Headers["Origin"] != null)
            Response.AddHeader("Access-Control-Allow-Origin" , Request.Headers["Origin"]);
        else
            Response.AddHeader("Access-Control-Allow-Origin" , "*");
    }
}
1
QA Collective

そしてDjangoでもう一つの答え。単一のビューで複数のドメインからのCORSを許可するには、これが私のコードです。

def my_view(request):
    if 'HTTP_Origin' in request.META.keys() and request.META['HTTP_Origin'] in ['http://allowed-unsecure-domain.com', 'https://allowed-secure-domain.com', ...]:
        response = my_view_response() # Create your desired response data: JsonResponse, HttpResponse...
        # Then add CORS headers for access from delivery
        response["Access-Control-Allow-Origin"] = request.META['HTTP_Origin']
        response["Access-Control-Allow-Methods"] = "GET" # "GET, POST, PUT, DELETE, OPTIONS, HEAD"
        response["Access-Control-Max-Age"] = "1000"  
        response["Access-Control-Allow-Headers"] = "*"  
        return response
1
Silvain

サブドメインを一致させるためのPHPコード例。

if( preg_match("/http:\/\/(.*?)\.yourdomain.example/", $_SERVER['HTTP_Origin'], $matches )) {
        $theMatch = $matches[0];
        header('Access-Control-Allow-Origin: ' . $theMatch);
}
1
blak3r

HTTP_Originはすべてのブラウザで使用されているわけではありません。 HTTP_ORIGINはどれくらい安全ですか? 私にとっては、FFで空になります。
自分のサイトへのアクセスを許可するサイトにサイトIDを送信させ、次にそのIDを持つレコードを自分のDBでチェックし、SITE_URL列の値(www.yoursite.com)を取得します。 

header('Access-Control-Allow-Origin: http://'.$row['SITE_URL']);

有効なサイトIDを介して送信する場合でも、要求はそのサイトIDに関連付けられた私のDBにリストされているドメインからのものである必要があります。

1
mathius1

ASMXサービスの複数ドメインアクセスを容易にするために、global.asaxファイルにこの関数を作成しました。

protected void Application_BeginRequest(object sender, EventArgs e)
{
    string CORSServices = "/account.asmx|/account2.asmx";
    if (CORSServices.IndexOf(HttpContext.Current.Request.Url.AbsolutePath) > -1)
    {
        string allowedDomains = "http://xxx.yyy.example|http://aaa.bbb.example";

        if(allowedDomains.IndexOf(HttpContext.Current.Request.Headers["Origin"]) > -1)
            HttpContext.Current.Response.AddHeader("Access-Control-Allow-Origin", HttpContext.Current.Request.Headers["Origin"]);

        if(HttpContext.Current.Request.HttpMethod == "OPTIONS")
            HttpContext.Current.Response.End();
    }
}

これにより、CORSによるOPTIONS動詞の処理も可能になります。

1
Derek Wade

以下の答えはC#に固有のものですが、この概念はすべての異なるプラットフォームに適用できるはずです。

Web APIからのクロスオリジンリクエストを許可するには、アプリケーションへのオプションリクエストを許可し、コントローラレベルで下記の注釈を追加する必要があります。

[EnableCors(UrlString、Header、Method)]起点にはs文字列のみを渡すことができます。リクエストに複数のURLを渡す場合はSOをカンマ区切り値として渡します。

UrlString = " https://a.hello.com、https://b.hello.com "

0
sakshi agrawal

SSLを介した広告配信 およびRFC自体の 文法 に関するGoogleのサポート回答は、URLをスペースで区切ることができることを示しているようです。さまざまなブラウザでこれがどの程度よくサポートされているのかわからない。

0
Bob Aman

私のようにCORSを使用して動作させるために非常に多くのコード例を試してみると、実際に動作するかどうかを試すために最初にキャッシュをクリアする必要があります。サーバー上で削除されます(まだキャッシュに保存されているため)。

例えば CTRL + SHIFT + DEL Google Chromeでキャッシュを削除します。

これは私が多くの純粋な.htaccess解決策を試した後に私がこのコードを使うのを助けました、そしてこれは(少なくとも私にとっては)唯一の解決策のようでした:

    Header add Access-Control-Allow-Origin "http://google.com"
    Header add Access-Control-Allow-Headers "authorization, Origin, user-token, x-requested-with, content-type"
    Header add Access-Control-Allow-Methods "PUT, GET, POST, DELETE, OPTIONS"

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

また、多くの解決策でHeader set ...と入力する必要があると言われていますが、それはHeader add ...であることが広く知られています。これが私のように今何時間も同じ問題を抱えている誰かに役立つことを願っています。

0
AlexioVay

Access-Control-Allow-Originヘッダーに指定できるOriginは1つだけです。ただし、リクエストに応じて、応答にオリジンを設定できます。また、Varyヘッダーを設定することを忘れないでください。 PHPでは、次のことを行います。

    /**
     * Enable CORS for the passed origins.
     * Adds the Access-Control-Allow-Origin header to the response with the Origin that matched the one in the request.
     * @param array $origins
     * @return string|null returns the matched Origin or null
     */
    function allowOrigins($origins)
    {
        $val = $_SERVER['HTTP_Origin'] ?? null;
        if (in_array($val, $origins, true)) {
            header('Access-Control-Allow-Origin: '.$val);
            header('Vary: Origin');

            return $val;
        }

        return null;
    }

  if (allowOrigins(['http://localhost', 'https://localhost'])) {
      echo your response here, e.g. token
  }
0
Simon