Поддомены, порты и протоколы подстановки под контролем доступа-Разрешения-Origin
Я пытаюсь включить CORS для всех поддоменов, портов и протокола.
Например, я хочу иметь возможность запускать запрос XHR из http://sub.mywebsite.com:8080/ в https://www.mywebsite.com/ *
Как правило, я хотел бы включить запрос от совпадения истоков (и ограничен):
//*.mywebsite.com:*/*
Ответы
Ответ 1
Основываясь на DaveRandom answer, я также играл вокруг и нашел немного более простое решение Apache, которое дает тот же результат (Access-Control-Allow-Origin
установлен на текущий конкретный протокол + домен + порт динамически) без использования правил перезаписи:
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"
И что это.
Те, кто хочет включить CORS в родительском домене (например, mywebsite.com) в дополнение ко всем своим поддоменам, могут просто заменить регулярное выражение в первой строке следующим:
^(https?://(?:.+\.)?mywebsite\.com(?::\d{1,5})?)$
.
Примечание. Для соответствия спецификаций и правильного поведения кэширования ВСЕГДА добавьте заголовок ответа Vary: Origin
для ресурсов с поддержкой CORS, Запросы CORS и адреса из запрещенного источника (см. пример почему).
Ответ 2
Спецификация CORS - это все или ничего. Он поддерживает только *
, null
или точный протокол + домен + порт: http://www.w3.org/TR/cors/#access-control-allow-origin-response-header
Серверу необходимо будет проверить заголовок источника с помощью регулярного выражения, а затем вы можете повторить исходное значение в заголовке ответа Access-Control-Allow-Origin.
Ответ 3
EDIT: используйте @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?://(?:.+?\.)?\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 регулярного выражения.
Ответ 4
Я отвечаю на этот вопрос, потому что принятый ответ не может соответствовать основному домену и работает только для поддомена. Кроме того, группировка регулярных выражений является хитом производительности, что необязательно.
Например: он не будет отправлять заголовки CORS для http://mywebsite.com, пока работает для 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"
Чтобы включить ваш сайт, вы просто помещаете свой сайт вместо "mywebsite.com" в вышеуказанную конфигурацию Apache.
Чтобы разрешить несколько сайтов:
SetEnvIf Origin "http(s)?://(.+\.)?(othersite\.com|mywebsite\.com)(:\d{1,5})?$" CORS=$0
Тестирование После развертывания:
Следующий сбойный ответ должен иметь заголовок "Access-Control-Allow-Origin" после изменения.
curl -X GET -H "Origin: http://examplesite1.com" --verbose http://examplesite2.com/query
Ответ 5
Мне нужно было только 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'),
Ответ 6
При настройке Access-Control-Allow-Origin
в.htaccess выполняется только следующее:
SetEnvIf Origin "http(s)?://(.+\.)?domain\.com(:\d{1,5})?$" CRS=$0
Header always set Access-Control-Allow-Origin "%{CRS}e" env=CRS
Я попробовал несколько других предложенных ключевых слов Header append
, Header set
, никто не работал, как было предложено во многих ответах на SO, хотя я понятия не имею, являются ли эти ключевые слова устаревшими или недействительными для 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]
Ответ 7
У нас были похожие проблемы с Font Awesome в статическом домене без файлов cookie при чтении шрифтов из домена cookie (www.domain.tld), и этот пост стал нашим героем. См. здесь: Как мне исправить & # 39; Отсутствующий заголовок ответа для общего ресурса (CORS) & # 39; проблема с веб-шрифтом?
Для типов 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>
Супер Безопасный, Супер Элегантный. Вам это нравится: вам не нужно открывать пропускную способность ваших серверов для типов воров/горячих ссылок.
Реквизит: @Noyo @DaveRandom @pratap-koritala
(Я пытался оставить это как комментарий к принятому ответу, но пока не могу этого сделать)
Ответ 8
Похоже, исходный ответ был для pre 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"
Ответ 9
Мне пришлось немного изменить ответ Ларса, так как сиротство \
появилось в регулярном выражении, чтобы сравнить фактический хост (не обращая внимания на протокол или порт), и я хотел поддерживать домен 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']));
}
Ответ 10
Для Spring Boot я нашел это RegexCorsConfiguration
которое расширяет официальную CorsConfiguration
: https://github.com/looorent/spring-security-jwt/blob/master/src/main/java/be/loorent/security/jwt/RegexCorsConfiguration.java
Ответ 11
С небольшим изменением ответа Ларса.
<?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;