我正在尝试为所有子域,端口和协议启用CORS。
例如,我希望能够运行从http://sub.mywebsite.com:8080/到https://www.mywebsite.com/的XHR请求*
通常情况下,我想从匹配(并限于)的原点启用请求:
//*.mywebsite.com:*/*
答案 0 :(得分:220)
CORS规范是全有或全无。它仅支持*
,null
或确切的协议+域+端口:http://www.w3.org/TR/cors/#access-control-allow-origin-response-header
您的服务器需要使用正则表达式验证原始标头,然后您可以在Access-Control-Allow-Origin响应标头中回显原始值。
答案 1 :(得分:166)
基于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"
就是这样。
除了所有子域之外,想要在父域(例如mywebsite.com)上启用CORS的人可以简单地用第一行替换第一行中的正则表达式:
^(https?://(?:.+\.)?mywebsite\.com(?::\d{1,5})?)$
。
注意:对于spec compliance和正确的缓存行为,总是为启用CORS的资源添加Vary: Origin
响应头,即使对于非CORS请求和来自不允许源的请求也是如此(请参阅{ {3}})。
答案 2 :(得分:58)
编辑:使用@Noyo's solution代替此。它更简单,更清晰,在负载下可能性能更高。
原始答案仅限于此处用于历史目的!!
我做了一些解决这个问题的工作,并提出了可与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匹配部分来控制允许变化的元素(协议,端口)。
答案 3 :(得分:14)
我正在回答这个问题,因为 接受的答案 与主域名不匹配,只适用于子域名。此外,正则表达式分组是性能损失,这是不必要的。
工作时,它不会发送http://somedomain.mywebsite.com/的CORS标头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
部署后进行测试:
以下卷曲响应应在更改后具有“Access-Control-Allow-Origin”标题。
curl -X GET -H "Origin: http://examplesite1.com" --verbose http://examplesite2.com/query
答案 4 :(得分:8)
我需要一个仅限PHP的解决方案,以防有人需要它。它需要一个允许的输入字符串,如&#34; * .example.com&#34;如果输入匹配,则返回请求标头服务器名称。
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'),
答案 5 :(得分:3)
在.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 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]
答案 6 :(得分:1)
当从“cookie域”(www.domain.tld)读取字体时,我们在静态“无cookie”域上遇到类似问题的Font Awesome,这篇文章是我们的英雄。见这里:How can I fix the 'Missing Cross-Origin Resource Sharing (CORS) Response Header' webfont issue?
对于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
(我试图将此作为对已接受答案的评论,但我还不能这样做)
答案 7 :(得分:0)
看起来原来的答案是针对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"
答案 8 :(得分:0)
我不得不修改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']));
}
答案 9 :(得分:0)
对于 Spring Boot ,我发现此RegexCorsConfiguration
扩展了官方CorsConfiguration
:https://github.com/looorent/spring-security-jwt/blob/master/src/main/java/be/looorent/security/jwt/RegexCorsConfiguration.java
答案 10 :(得分:-1)
Lars回答略有变化。
<?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;
答案 11 :(得分:-1)
在我的情况下使用角度
在我的HTTP拦截器中,设置
with Credentials: true.
在请求的标题中