web-dev-qa-db-ja.com

Access-Control-Allow-Originのワイルドカードサブドメイン、ポート、およびプロトコル

すべてのサブドメイン、ポート、およびプロトコルに対してCORSを有効にしようとしています。

たとえば、 http://sub.mywebsite.com:8080/ から https://www.mywebsite.com/ *にXHRリクエストを実行できるようにします。

典型的には、私は起源からの要求を一致させたい(そしてそれに限定されたい)。

//*.mywebsite.com:*/*

257
Elie

DaveRandomの answer に基づいて、私はいろいろな書き換え規則を使用せずに同じ結果(Access-Control-Allow-Originが現在の特定のプロトコル+ドメイン+ポートに動的に設定される)を生成するわずかに単純なApacheソリューションも見つけました。

SetEnvIf Origin ^(https?://.+\.mywebsite\.com(?::\d{1,5})?)$   CORS_ALLOW_Origin=$1
Header append Access-Control-Allow-Origin  %{CORS_ALLOW_Origin}e   env=CORS_ALLOW_Origin
Header merge  Vary "Origin"

以上です。

すべてのサブドメインに加えて、親ドメイン(mywebsite.comなど)でCORSを有効にしたい場合は、最初の行の正規表現を次のように置き換えるだけです。

^(https?://(?:.+\.)?mywebsite\.com(?::\d{1,5})?)$

注: specへの準拠 および正しいキャッシング動作のために、CORS以外の要求や許可されていないOriginからの要求に対しても、常にVary: Origin応答ヘッダーを追加してください( exampleを参照 ) 。

163
Noyo

CORSの仕様は全か無かです。それは*nullまたは正確なプロトコル+ドメイン+ポートのみをサポートします: http://www.w3.org/TR/cors/#access-control-allow-Origin-response-header

サーバーは正規表現を使用してOriginヘッダーを検証する必要があります。その後、Access-Control-Allow-OriginレスポンスヘッダーのOrigin値をエコーすることができます。

219
monsur

_ edit _ :この代わりに @ Noyoの解決策 を使用してください。それはより単純で、より明確で、そして負荷のもとではもっとずっとパフォーマンスが高いと思われます。

歴史的な目的のためだけにここに元の回答があります!!


私はこの問題をいくつか試してみて、Apacheで動作するこの再利用可能な.htaccess(またはhttpd.conf)ソリューションを思いついた。

<IfModule mod_rewrite.c>
<IfModule mod_headers.c>
    # Define the root domain that is allowed
    SetEnvIf Origin .+ ACCESS_CONTROL_ROOT=yourdomain.com

    # Check that the Origin: matches the defined root domain and capture it in
    # an environment var if it does
    RewriteEngine On
    RewriteCond %{ENV:ACCESS_CONTROL_ROOT} !=""
    RewriteCond %{ENV:ACCESS_CONTROL_Origin} =""
    RewriteCond %{ENV:ACCESS_CONTROL_ROOT}&%{HTTP:Origin} ^([^&]+)&(https?://(?:.+?\.)?\1(?::\d{1,5})?)$
    RewriteRule .* - [E=ACCESS_CONTROL_Origin:%2]

    # Set the response header to the captured value if there was a match
    Header set Access-Control-Allow-Origin %{ACCESS_CONTROL_Origin}e env=ACCESS_CONTROL_Origin
</IfModule>
</IfModule>

ブロックの一番上にあるACCESS_CONTROL_ROOT変数をあなたのルートドメインに設定するだけで、それがあなたのドメインにマッチすればOrigin:リクエストヘッダ値をAccess-Control-Allow-Origin:レスポンスヘッダ値としてクライアントにエコーバックします。

sub.mydomain.comとしてACCESS_CONTROL_ROOTを使うことができ、それは起源をsub.mydomain.com*.sub.mydomain.comに制限するでしょう(すなわち、それはドメインルートである必要はない)。変更が許可されている要素(プロトコル、ポート)は、正規表現のURIマッチング部分を変更することによって制御できます。

58
DaveRandom

承認された回答はプライマリドメインとは一致せず、サブドメインでしか機能しないためです。また、 正規表現のグループ化はパフォーマンスに影響を与える であり、これは必須ではありません。

例: http://mywebsite.com のCORSヘッダーは送信されません http://somedomain.mywebsite.com/ の動作

SetEnvIf Origin "http(s)?://(.+\.)?mywebsite\.com(:\d{1,5})?$" CORS=$0

Header set Access-Control-Allow-Origin "%{CORS}e" env=CORS
Header merge  Vary "Origin"

あなたのサイトを有効にするには、上記のApache設定であなたのサイトを "mywebsite.com"の代わりに置くだけです。

複数のサイトを許可するには:

SetEnvIf Origin "http(s)?://(.+\.)?(othersite\.com|mywebsite\.com)(:\d{1,5})?$" CORS=$0

テストデプロイ後のテスト:

次のcurlレスポンスは変更後に "Access-Control-Allow-Origin"ヘッダを持つべきです。

curl -X GET -H "Origin: http://examplesite1.com" --verbose http://examplesite2.com/query
14
Pratap Koritala

私はPHP専用のソリューションを必要としていたので、万が一誰かがそれを必要とする場合に備えて。 "* .example.com"のような許可された入力文字列を取り、入力が一致すればリクエストヘッダサーバ名を返します。

function getCORSHeaderOrigin($allowed, $input)
{
    if ($allowed == '*') {
        return '*';
    }

    $allowed = preg_quote($allowed, '/');

    if (($wildcardPos = strpos($allowed, '*')) !== false) {
        $allowed = str_replace('*', '(.*)', $allowed);
    }

    $regexp = '/^' . $allowed . '$/';

    if (!preg_match($regexp, $input, $matches)) {
        return 'none';
    }

    return $input;
}

そして、これがphpunitデータプロバイダのテストケースです。

//    <description>                            <allowed>          <input>                   <expected>
array('Allow Subdomain',                       'www.example.com', 'www.example.com',        'www.example.com'),
array('Disallow wrong Subdomain',              'www.example.com', 'ws.example.com',         'none'),
array('Allow All',                             '*',               'ws.example.com',         '*'),
array('Allow Subdomain Wildcard',              '*.example.com',   'ws.example.com',         'ws.example.com'),
array('Disallow Wrong Subdomain no Wildcard',  '*.example.com',   'example.com',            'none'),
array('Allow Double Subdomain for Wildcard',   '*.example.com',   'a.b.example.com',        'a.b.example.com'),
array('Don\'t fall for incorrect position',    '*.example.com',   'a.example.com.evil.com', 'none'),
array('Allow Subdomain in the middle',         'a.*.example.com', 'a.bc.example.com',       'a.bc.example.com'),
array('Disallow wrong Subdomain',              'a.*.example.com', 'b.bc.example.com',       'none'),
array('Correctly handle dots in allowed',      'example.com',     'exampleXcom',            'none'),
8
Lars

.htaccessでAccess-Control-Allow-Originを設定する場合、以下のみが機能しました:

SetEnvIf Origin "http(s)?://(.+\.)?domain\.com(:\d{1,5})?$" CRS=$0
Header always set Access-Control-Allow-Origin "%{CRS}e" env=CRS

他のいくつかの推奨キーワードを試してみましたHeader appendHeader setなしこれらのキーワードが古くなっているか、またはnginxに対して無効かどうかを考えます。

私の完全なソリューションは次のとおりです。

SetEnvIf Origin "http(s)?://(.+\.)?domain\.com(:\d{1,5})?$" CRS=$0
Header always set Access-Control-Allow-Origin "%{CRS}e" env=CRS
Header merge Vary "Origin"

Header always set Access-Control-Allow-Methods "GET, POST"
Header always set Access-Control-Allow-Headers: *

# Cached for a day
Header always set Access-Control-Max-Age: 86400

RewriteEngine On

# Respond with 200OK for OPTIONS
RewriteCond %{REQUEST_METHOD} OPTIONS
RewriteRule ^(.*)$ $1 [R=200,L]
3
AamirR

「cookieドメイン」(www.domain.tld)からフォントを読み取るときに、静的な「cookieなし」ドメインのFont Awesomeでも同様の問題がありました。この投稿は私たちのヒーローでした。こちらを参照してください。 'Missing Cross-Origin Resource Sharing(CORS)レスポンスヘッダ' Webfontの問題を修正するにはどうすればよいですか?

Copy/paste-rタイプの場合(そしていくつかの小道具を与えるために)、私はこれをすべての貢献からまとめてサイトルートの.htaccessファイルの先頭に追加しました。

<IfModule mod_headers.c> <IfModule mod_rewrite.c> SetEnvIf Origin "http(s)?://(.+\.)?(othersite\.com|mywebsite\.com)(:\d{1,5})?$" CORS=$0 Header set Access-Control-Allow-Origin "%{CORS}e" env=CORS Header merge Vary "Origin" </IfModule> </IfModule>

スーパーセキュア、スーパーエレガント。それを好む:あなたはあなたのサーバーの帯域幅をリソース窃盗犯/ hot-link-erタイプに開放する必要はありません。

への小道具:@Noyo @DaveRandom @ pratap-koritala

(私はこれを受け入れられた答えへのコメントとして残そうとしました、しかし私はまだそれをすることができません)

1
kanidrive

最初の答えはApache 2.4以前のものだったようです。私にはうまくいきませんでした。これが2.4で動くようにするために私が変更しなければならなかったものです。これは yourcompany.com の任意の深さのサブドメインで機能します。

SetEnvIf Host ^((?:.+\.)*yourcompany\.com?)$    CORS_ALLOW_Origin=$1
Header append Access-Control-Allow-Origin  %{REQUEST_SCHEME}e://%{CORS_ALLOW_Origin}e    env=CORS_ALLOW_Origin
Header merge  Vary "Origin"
0
Jack K

Spring Boot 公式のRegexCorsConfigurationを拡張するこのCorsConfigurationを見つけました: https://github.com/looorent/spring-security-jwt/blob/master/src/main/Java/be/looorent /security/jwt/RegexCorsConfiguration.Java

0
RiZKiT

孤立した\は正規表現になったので(プロトコルやポートに注意を払っていない)単に比較するために Lars ' を少し修正する必要があり、localhostをサポートしたいと思いました。私の本番ドメイン以外のドメイン。そのため、$allowedパラメータを配列に変更しました。

function getCORSHeaderOrigin($allowed, $input)
{
    if ($allowed == '*') {
        return '*';
    }

    if (!is_array($allowed)) {
        $allowed = array($allowed);
    }

    foreach ($allowed as &$value) {
        $value = preg_quote($value, '/');

        if (($wildcardPos = strpos($value, '\*')) !== false) {
            $value = str_replace('\*', '(.*)', $value);
        }
    }

    $regexp = '/^(' . implode('|', $allowed) . ')$/';

    $inputHost = parse_url($input, PHP_URL_Host);

    if ($inputHost === null || !preg_match($regexp, $inputHost, $matches)) {
        return 'none';
    }

    return $input;
}

使用方法は次のとおりです。

if (isset($_SERVER['HTTP_Origin'])) {
    header("Access-Control-Allow-Origin: " . getCORSHeaderOrigin(array("*.myproduction.com", "localhost"), $_SERVER['HTTP_Origin']));
}
0
Capricorn