Access-Control-Allow-Origin通配符子域名,端口和协议

我试图为所有子域,端口和协议启用CORS。

例如,我希望能够从http://sub.mywebsite.com:8080/运行XHR请求到https://www.mywebsite.com/ *

通常,我想启用来自匹配(和限制)的来源请求:

//*.mywebsite.com:*/*

基于DaveRandom的回答 ,我也玩弄了一下,发现了一个稍微简单一点的Apache解决scheme,它可以产生相同的结果( Access-Control-Allow-Origindynamic设置为当前特定协议+域+端口),而不使用任何重写规则:

 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_ROOTvariables设置为根域,并且它将在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;