Поддомены, порты и протоколы подстановочных знаков Access-Control-Allow-Origin

Я пытаюсь включить CORS для всех поддоменов, портов и протокола.

например, я хочу иметь возможность запускать запрос XHR изhttp://sub.mywebsite.com:8080/ до https://www.mywebsite.com/*

Как правило, я хотел бы включить запрос из сопоставления источников (и ограничен):

//*.mywebsite.com:*/*

8 ответов


на основе DaveRandom это ответ, Я также играл и нашел немного более простое решение Apache, которое дает тот же результат (Access-Control-Allow-Origin установлен текущий конкретный протокол + домен + порт динамически) без использования каких-либо правил перезаписи:

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

и это все.

те, кто хочет включить CORS в Родительском домене (например mywebsite.com) в дополнение ко всем своим поддоменам можно просто заменить регулярное выражение в первой строке на этот:

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

Примечание:соответствие спецификаций и правильное поведение кэширования, всегда добавляйте Vary: Origin заголовок ответа для ресурсов с поддержкой CORS, даже для запросов без CORS и из запрещенного источника (см. пример почему).


спецификация CORS-это все или ничего. Он поддерживает только *, null или точный протокол + домен + порт:http://www.w3.org/TR/cors/#access-control-allow-origin-response-header

ваш сервер должен будет проверить заголовок origin с помощью регулярного выражения, а затем вы можете повторить исходное значение в заголовке ответа Access-Control-Allow-Origin.


редактировать используйте решение@Noyo вместо этого. Это проще, понятнее и, вероятно, намного более эффективно под нагрузкой.

ОРИГИНАЛЬНЫЙ ОТВЕТ ОСТАВИЛ ЗДЕСЬ ТОЛЬКО ДЛЯ ИСТОРИЧЕСКИХ ЦЕЛЕЙ!!


Я немного поиграл с этой проблемой и придумал этот многоразовый.htaccess (или httpd.conf) решение, которое работает с Apache:

<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?://(?:.+?\.)?(?::\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 части регулярного выражения.


я отвечаю на этот вопрос, потому что принято отвечать не может соответствовать основной домен и поддомен. Кроме того,группировка регулярных выражений-это хит производительности, что не обязательно.

например: не отправлять заголовки CORS для http://mywebsite.com пока работает на http://somedomain.mywebsite.com/

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

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

чтобы включить для вашего сайта, вы просто поместите свой сайт вместо "mywebsite.com" в приведенной выше конфигурации Apache.

чтобы разрешить несколько сайтов:

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

тестирование после развертывания:

следующий ответ curl должен иметь заголовок" Access-Control-Allow-Origin " после изменения.

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

мне нужно было только 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'),

у нас были аналогичные проблемы с Font Awesome в статическом домене " cookie-less "при чтении шрифтов из" cookie-домена " (www.домен.tld) и этот пост был нашим героем. Смотрите здесь: Как я могу исправить "отсутствующий заголовок ответа совместного использования ресурсов (CORS)" webfont?

для типов copy / paste-r (и дать некоторые реквизиты) я собрал это вместе из всех вкладов и добавил его в верхнюю часть .файл htaccess сайта root:

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

Супер Безопасный, Супер Элегантный. Вам не нужно открывать пропускную способность своих серверов для типов воров ресурсов / горячих ссылок.

реквизит to:@Noyo @ DaveRandom @pratap-koritala

(Я попытался оставить это как комментарий к принятому ответу, но я пока не могу этого сделать)


похоже, что исходный ответ был для pre Apache 2.4. Это не сработало для меня. Вот что мне пришлось изменить, чтобы заставить его работать в 2.4. Это будет работать для любой глубины поддомена yourcompany.com.

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

с небольшим изменением ответа Ларса.

<?php
function validateOrigin($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;
}

// CORS Preflight
if($_SERVER['REQUEST_METHOD'] === 'OPTIONS')
{
    header('Access-Control-Allow-Origin: '.validateOrigin('https://*.domain.com', $_SERVER['HTTP_ORIGIN']));
    header('X-Response-Code: 204', true, 204);
    header('Access-Control-Allow-Methods: GET');
    header('Access-Control-Allow-Headers: Content-Type');
} elseif($_SERVER['REQUEST_METHOD'] === 'GET'
    && isset($_GET['VARIABLEHERE'])
) {
    // CODE HERE

    if($info["http_code"] === 200){
        // 200 OK
        header('Content-type: application/json; charset=utf-8');
        // CORS headers
        header('Access-Control-Allow-Origin: '.validateOrigin('https://*.domain.com', $_SERVER['HTTP_ORIGIN']));
        echo $response;
    } else {
        header('X-Service-Response-Code: '.$info["http_code"], true, $info["http_code"]);
    }
} else {
    // 400 bad request.
    header('X-Response-Code: 400', true, 400);
}

exit;