Access-Control-Allow-Origin通配符子域名,端口和协议
我试图为所有子域,端口和协议启用CORS。
例如,我希望能够从http://sub.mywebsite.com:8080/运行XHR请求到https://www.mywebsite.com/ *
通常,我想启用来自匹配(和限制)的来源请求:
//*.mywebsite.com:*/*
基于DaveRandom的回答 ,我也玩弄了一下,发现了一个稍微简单一点的Apache解决scheme,它可以产生相同的结果( Access-Control-Allow-Origin
dynamic设置为当前特定协议+域+端口),而不使用任何重写规则:
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以及其所有子域的人可以简单地用第一行代替正则expression式:
^(https?://(?:.+\.)?mywebsite\.com(?::\d{1,5})?)$
。
注意:为了符合规范和正确的caching行为,即使对于非CORS请求和来自不允许来源的请求,请始终为启用CORS的资源添加Vary: Origin
响应标头(请参阅示例原因 )。
CORS规范是全有或全无。 它只支持*
, null
或确切的协议+域+端口: http : //www.w3.org/TR/cors/#access-control-allow-origin-response-header
您的服务器将需要使用正则expression式validation源标头,然后您可以在Access-Control-Allow-Origin响应标头中回显原始值。
编辑 :使用@ Noyo的解决scheme,而不是这一个。 在负载下更简单,更清晰,可能性更高。
原来的回答只是为了历史的目的!
我做了一些解决这个问题的东西,想出了这个可以和Apache一起工作的可重用的.htaccess(或者httpd.conf)解决scheme:
<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
variables设置为根域,并且它将在Access-Control-Allow-Origin:
响应标头值中将Origin:
请求标头值回送给客户端,如果它与您的域匹配的话。
还要注意的是,你可以使用sub.mydomain.com
作为ACCESS_CONTROL_ROOT
,它会将来源限制为sub.mydomain.com
和*.sub.mydomain.com
(即它不一定是域根)。 允许变化的元素(协议,端口)可以通过修改正则expression式的URI匹配部分来控制。
我正在回答这个问题,因为接受的答案不能匹配主域,只适用于子域。 此外, 正则expression式分组是一个性能打击 ,这是没有必要的。
例如:它不会发送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"
要启用您的网站,您只需在上面的“Apacheconfiguration”中将您的网站replace为“mywebsite.com”即可。
要允许多个网站:
SetEnvIf Origin "http(s)?://(.+\.)?(othersite\.com|mywebsite\.com)(:\d{1,5})?$" CORS=$0
testing部署完成后:
下面的curl响应在更改后应该具有“Access-Control-Allow-Origin”标题。
curl -X GET -H "Origin: http://examplesite1.com" --verbose http://examplesite2.com/query
我需要一个PHP的解决scheme,以防万一有人需要它。 它接受一个允许的inputstring,如“* .example.com”,并返回请求头的服务器名称,如果input匹配。
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数据提供者的testing用例:
// <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', 'abexample.com', 'abexample.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'),
拉尔斯的答案略有改变。
<?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;