通常,我想启用来自匹配(且仅限于)的来源的请求:
//*.mywebsite.com:*/*
#1 楼
根据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"
就是这样。
除了所有子域之外,还希望在父域(例如mywebsite.com)上启用CORS的人可以简单地替换正则表达式在第一行中:
^(https?://(?:.+\.)?mywebsite\.com(?::\d{1,5})?)$
。注意:为了符合规范并纠正缓存行为,始终为启用了CORS的资源添加
Vary: Origin
响应标头,即使对于非CORS请求以及来自不允许来源的请求(请参见示例)。#2 楼
CORS规格全有或全无。它仅支持*
,null
或确切的协议+域+端口:http://www.w3.org/TR/cors/#access-control-allow-origin-response-header 您的服务器将需要使用正则表达式验证原始标头,然后可以在
Access-Control-Allow-Origin
响应标头中回显原始值。评论
@Dexter“ null”可用于响应“ null”来源,例如从file://方案发出CORS请求时。
– monsur
2014年3月3日4:16在
极短视的是,CORS规范不支持OP的确切用例。
–aroth
2014年10月8日,0:55
@aroth:并非如此,该规范允许实现使用他们想要的任何匹配语法。对于不支持该用例的实现来说,这将是非常短视的。换句话说,您为服务器指定的不是ACAO值,后者只是协议详细信息。我的假设是,存在一个安全方案需要回显的原点或从中得到好处,但是幼稚的实现只需要说“ OK”即可。
–tne
2014年11月12日9:40
2015年更新:此答案不完整,可能会导致缓存问题,因此应视为有害。请参阅以下我的答案以获取正确的实现(适用于Apache)和说明:stackoverflow.com/a/27990162/357774。另外,正如@neoth所指出的那样,该规范实际上确实允许OP的确切用例:w3.org/TR/cors/#resource-implementation。正如这个答案所指出的,这取决于服务器来实现。如上面提到的答案所示,这可以分三行完成。
– Noyo
15年8月26日在13:35
@Noyo-我会澄清我的原始意思。从根本上来说,CORS规范并不严格要求所有实施CORS的服务器都为OP的确切用例提供自动的内置支持。让每个用户使用自定义PHP代码,重写规则或所拥有的知识来构建自己的垫片,这是造成碎片,错误和灾难的秘诀。服务器开发人员应该比这更好地了解;如果不这样做,CORS规范应强制他们这样做。
–aroth
2015年8月27日0:47
#3 楼
编辑:使用@ Noyo的解决方案,而不是此解决方案。它在负载下更简单,更清晰,而且性能可能更高。此处仅保留原始答案,仅供历史用途!
我做了一些尝试问题,并提出了与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?://(?:.+?\.)?(?::\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 楼
我正在回答这个问题,因为遵循regex分组不能接受已接受的答案,这对性能造成了影响,这不是必需的。
不能匹配主域,并且仅适用于子域。
例如:当为http://somedomain.mywebsite.com/工作时,它不会为http://mywebsite.com发送CORS标头。
SetEnvIf Origin "http(s)?://(.+\.)?mywebsite\.com(:\d{1,5})?$" CORS=SetEnvIf Origin "http(s)?://(.+\.)?(othersite\.com|mywebsite\.com)(:\d{1,5})?$" CORS=curl -X GET -H "Origin: http://examplesite1.com" --verbose http://examplesite2.com/query
Header set Access-Control-Allow-Origin "%{CORS}e" env=CORS
Header merge Vary "Origin"
要启用您的网站,只需在上述Apache配置中将您的网站替换为“ mywebsite.com”即可。
要允许多个网站:
q4312078q
部署后的测试:
更改后,以下卷曲响应应具有“ Access-Control-Allow-Origin”标头。
q4312078q
#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'),
评论
+1,已编辑为使用preg_quote(),因为这样做是正确的方法(即使。是DNS名称中唯一有效的regexp元字符,preg_quote()更好地描述了预期的操作)
– DaveRandom
15年7月20日在0:13
应该澄清的是,根据规范,没有一个消息不是对报头来说在语义上有效的值(或者至少没有按照其含义行事)。这样,返回null;对于该分支可能更有意义,在这种情况下,不应将标头发送给客户端,因此调用方应对其进行检查。
– DaveRandom
2015年7月20日在0:19
preg_quote()将加*号,因此例如str_replace()留下一个孤立的“ \”。
–克里斯托弗·布巴赫(Christoffer Bubach)
16年11月29日在16:37
这很有用,我花了一些时间在CORS问题上,直到我意识到我的站点在ajax中具有“ www”,但在永久链接结构中却没有-您的解决方案帮助我了解了问题所在并为我解决了问题。
–索尔
18年6月30日在3:22
#6 楼
在.htaccess中设置Access-Control-Allow-Origin
时,只有以下工作有效:SetEnvIf Origin "http(s)?://(.+\.)?domain\.com(:\d{1,5})?$" CRS=SetEnvIf Origin "http(s)?://(.+\.)?domain\.com(:\d{1,5})?$" CRS=q4312078q
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 ^(.*)$ [R=200,L]
Header always set Access-Control-Allow-Origin "%{CRS}e" env=CRS
我尝试了其他几个建议的关键字
Header append
,Header set
,但都没有按SO的许多答案中的建议工作,尽管我不知道这些关键字是否过时或对nginx无效。这是我的完整解决方案:
q4312078q
#7 楼
从“ cookie域”(www.domain.tld)读取字体时,我们在静态“不含cookie的”域上遇到了Font Awesome的类似问题,而本文是我们的英雄。请参阅此处:如何解决“缺少跨域资源共享(CORS)响应标题” webfont问题?对于copy / paste-r类型(并提供一些道具),我进行了拼凑将所有贡献汇总在一起,并将其添加到网站根目录的.htaccess文件顶部:
<IfModule mod_headers.c>
<IfModule mod_rewrite.c>
SetEnvIf Origin "http(s)?://(.+\.)?(othersite\.com|mywebsite\.com)(:\d{1,5})?$" CORS=q4312078q
Header set Access-Control-Allow-Origin "%{CORS}e" env=CORS
Header merge Vary "Origin"
</IfModule>
</IfModule>
超级安全,超级优雅。喜欢它:您不必为资源窃贼/热链接器类型打开服务器带宽。
道具:@Noyo @DaveRandom @ pratap-koritala
(我尝试将其作为对已接受答案的注释,但我还不能这样做)
#8 楼
原始答案似乎是针对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"
#9 楼
对于Spring Boot,我发现了这个RegexCorsConfiguration
,它扩展了官方CorsConfiguration
:https://github.com/looorent/spring-security-jwt/blob/master/src/main/java/be/looorent/security/jwt/RegexCorsConfiguration.java #10 楼
我不得不修改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']));
}
#11 楼
在我的HTTP拦截器中使用angular的情况下,我在请求的标头中设置了
with Credentials: true.
评论
当访问者在使用相同字体的多个子域之间跳转时,我们几乎遇到了这种情况(不是Vary Origin),并且行为不当。字体和access-control-origin标头也已缓存。我对此做了一些更改:如果请求来自我们允许的域之一,则使用“ Access-Control-Allow-Origin *”。也许这是通过我们以前没有的“可变起源”解决的……现在也添加了它。
–埃里克·梅尔克森(Erik Melkersson)
2015年12月4日,11:48
不适用于主体域“ mywebsite.com”
–biology.info
16年4月25日在15:43
@pgmann,在此上下文中无需转义//,因为Apache conf不使用斜杠分隔的正则表达式。 Regexr抱怨是因为在这种情况下,斜杠作为分隔符具有特殊含义。
– Noyo
16年5月4日在13:10
'Access-Control-Allow-Origin'标头包含多个值'^(https?://(?:。+。)?aerofotea.com(?:: d {1,5})?)$',但是只允许一个。因此,不允许访问来源“ http://local.aerofotea.com”。
–王A
17-6-10上午11:04
您将此代码放在哪里? .htaccess或在apache虚拟主机配置中?
– Glen
19年3月29日在18:54