访问控制允许来源多源域?
-
11-09-2019 - |
题
有没有办法允许使用多个跨域 Access-Control-Allow-Origin
标头?
我知道 *
, ,但是太开放了。我真的只想允许几个域。
举个例子,像这样:
Access-Control-Allow-Origin: http://domain1.example, http://domain2.example
我已经尝试过上面的代码,但它似乎在 Firefox 中不起作用。
是否可以指定多个域,还是只能指定一个域?
解决方案
听起来就像是推荐的方式做到这一点是让你的服务器读取来自客户端的Origin标,比较,为域的列表,你想允许的,如果它匹配,呼应了Origin
头的值回到客户端在响应中Access-Control-Allow-Origin
报头。
使用.htaccess
你可以做这样的:
# ----------------------------------------------------------------------
# Allow loading of external fonts
# ----------------------------------------------------------------------
<FilesMatch "\.(ttf|otf|eot|woff|woff2)$">
<IfModule mod_headers.c>
SetEnvIf Origin "http(s)?://(www\.)?(google.com|staging.google.com|development.google.com|otherdomain.example|dev02.otherdomain.example)$" AccessControlAllowOrigin=$0
Header add Access-Control-Allow-Origin %{AccessControlAllowOrigin}e env=AccessControlAllowOrigin
Header merge Vary Origin
</IfModule>
</FilesMatch>
其他提示
另一种解决方案我使用在PHP:
$http_origin = $_SERVER['HTTP_ORIGIN'];
if ($http_origin == "http://www.domain1.com" || $http_origin == "http://www.domain2.com" || $http_origin == "http://www.domain3.com")
{
header("Access-Control-Allow-Origin: $http_origin");
}
这为我工作:
SetEnvIf Origin "^http(s)?://(.+\.)?(domain\.example|domain2\.example)$" origin_is=$0
Header always set Access-Control-Allow-Origin %{origin_is}e env=origin_is
放在.htaccess
当,它将为确保正常工作。
我与WOFF的字体同样的问题,多个子域必须具有访问权限。为了让子域我说这样的事情给我的httpd.conf:
SetEnvIf Origin "^(.*\.example\.com)$" ORIGIN_SUB_DOMAIN=$1
<FilesMatch "\.woff$">
Header set Access-Control-Allow-Origin "%{ORIGIN_SUB_DOMAIN}e" env=ORIGIN_SUB_DOMAIN
</FilesMatch>
有关多个域,你可以只改变正则表达式中SetEnvIf
。
下面是如何呼应Origin标回来,如果它匹配与Nginx的您的域名,如果你想成为一个字体多个子域,这是有用的:
location /fonts {
# this will echo back the origin header
if ($http_origin ~ "example.org$") {
add_header "Access-Control-Allow-Origin" $http_origin;
}
}
下面是我做用于正在由AJAX请求的PHP应用
$request_headers = apache_request_headers();
$http_origin = $request_headers['Origin'];
$allowed_http_origins = array(
"http://myDumbDomain.example" ,
"http://anotherDumbDomain.example" ,
"http://localhost" ,
);
if (in_array($http_origin, $allowed_http_origins)){
@header("Access-Control-Allow-Origin: " . $http_origin);
}
如果发出请求的原点由我的服务器允许的,返回$http_origin
本身作为Access-Control-Allow-Origin
报头的值而不是返回*
通配符。
有一个缺点,你应该知道的:只要你出的源文件到一个CDN(或任何其他服务器不允许脚本),或者如果你的文件是在代理缓存,改变响应基于“产地”请求头将无法工作。
有关多个域,在您的.htaccess
:
<IfModule mod_headers.c>
SetEnvIf Origin "http(s)?://(www\.)?(domain1.example|domain2.example)$" AccessControlAllowOrigin=$0$1
Header add Access-Control-Allow-Origin %{AccessControlAllowOrigin}e env=AccessControlAllowOrigin
Header set Access-Control-Allow-Credentials true
</IfModule>
有关的Nginx用户,以允许多个域CORS。我喜欢@马歇尔的例子,虽然他只anwers匹配一个域。要匹配域名的列表和子这个表达式使其缓和与字体的工作:
location ~* \.(?:ttf|ttc|otf|eot|woff|woff2)$ {
if ( $http_origin ~* (https?://(.+\.)?(domain1|domain2|domain3)\.(?:me|co|com)$) ) {
add_header "Access-Control-Allow-Origin" "$http_origin";
}
}
此将只回声“访问控制允许来源”报头,与结构域的给定的列表匹配。
有关IIS 7.5+与URL重写2.0模块安装请参阅该SO回答
下面对Java Web应用程序的解决方案,基于从yesthatguy答案。
我使用泽西REST 1.x的
配置在web.xml要意识到泽西REST和CORSResponseFilter
的 <!-- Jersey REST config -->
<servlet>
<servlet-name>JAX-RS Servlet</servlet-name>
<servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class>
<init-param>
<param-name>com.sun.jersey.api.json.POJOMappingFeature</param-name>
<param-value>true</param-value>
</init-param>
<init-param>
<param-name>com.sun.jersey.spi.container.ContainerResponseFilters</param-name>
<param-value>com.your.package.CORSResponseFilter</param-value>
</init-param>
<init-param>
<param-name>com.sun.jersey.config.property.packages</param-name>
<param-value>com.your.package</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>JAX-RS Servlet</servlet-name>
<url-pattern>/ws/*</url-pattern>
</servlet-mapping>
下面是CORSResponseFilter代码
import com.sun.jersey.spi.container.ContainerRequest;
import com.sun.jersey.spi.container.ContainerResponse;
import com.sun.jersey.spi.container.ContainerResponseFilter;
public class CORSResponseFilter implements ContainerResponseFilter{
@Override
public ContainerResponse filter(ContainerRequest request,
ContainerResponse response) {
String[] allowDomain = {"http://localhost:9000","https://my.domain.example"};
Set<String> allowedOrigins = new HashSet<String>(Arrays.asList (allowDomain));
String originHeader = request.getHeaderValue("Origin");
if(allowedOrigins.contains(originHeader)) {
response.getHttpHeaders().add("Access-Control-Allow-Origin", originHeader);
response.getHttpHeaders().add("Access-Control-Allow-Headers",
"origin, content-type, accept, authorization");
response.getHttpHeaders().add("Access-Control-Allow-Credentials", "true");
response.getHttpHeaders().add("Access-Control-Allow-Methods",
"GET, POST, PUT, DELETE, OPTIONS, HEAD");
}
return response;
}
}
如上所述,Access-Control-Allow-Origin
应该是唯一的和Vary
应设置为Origin
如果是后面的CDN(内容分发网络)。
我的Nginx的配置的主要部分:
if ($http_origin ~* (https?://.*\.mydomain.example(:[0-9]+)?)) {
set $cors "true";
}
if ($cors = "true") {
add_header 'Access-Control-Allow-Origin' "$http_origin";
add_header 'X-Frame-Options' "ALLOW FROM $http_origin";
add_header 'Access-Control-Allow-Credentials' 'true';
add_header 'Vary' 'Origin';
}
也许我错了,但据我可以看到Access-Control-Allow-Origin
有"origin-list"
作为参数。
通过定义一个origin-list
是:
origin = "origin" ":" 1*WSP [ "null" / origin-list ]
origin-list = serialized-origin *( 1*WSP serialized-origin )
serialized-origin = scheme "://" host [ ":" port ]
; <scheme>, <host>, <port> productions from RFC3986
和从这一点,我认为不同的起源被接纳并应的空间分离强>
我挣扎设置此运行HTTPS一个域,所以我本人将共享解决方案。我用下面的指令在我的的httpd.conf 的文件:
<FilesMatch "\.(ttf|otf|eot|woff)$">
SetEnvIf Origin "^http(s)?://(.+\.)?example\.com$" AccessControlAllowOrigin=$0
Header set Access-Control-Allow-Origin %{AccessControlAllowOrigin}e env=AccessControlAllowOrigin
</FilesMatch>
更改example.com
你的域名。在的httpd.conf 的文件中添加这里面<VirtualHost x.x.x.x:xx>
。请注意,如果您VirtualHost
有一个端口后缀(如:80
),那么这个指令将不适用于HTTPS,所以你还需要去的的/ etc / apache2的/网站可用/默认SSL 的和添加相同的指令在该文件中,<VirtualHost _default_:443>
部的内侧。
一旦配置文件被更新时,你将需要运行在终端中的以下命令:
a2enmod headers
sudo service apache2 reload
如果您有字体麻烦,使用:
<FilesMatch "\.(ttf|ttc|otf|eot|woff)$">
<IfModule mod_headers>
Header set Access-Control-Allow-Origin "*"
</IfModule>
</FilesMatch>
有关ExpressJS应用程序可以使用:
app.use((req, res, next) => {
const corsWhitelist = [
'https://domain1.example',
'https://domain2.example',
'https://domain3.example'
];
if (corsWhitelist.indexOf(req.headers.origin) !== -1) {
res.header('Access-Control-Allow-Origin', req.headers.origin);
res.header('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept');
}
next();
});
HTTP_ORIGIN不使用所有的浏览器。 安全性如何HTTP_ORIGIN?对我来说,它出现在空FF。结果 我有我允许访问我的网站发送了一个网站ID的网站,然后我检查我的数据库与该ID的记录,并获得SITE_URL列值(www.yoursite.com)。
header('Access-Control-Allow-Origin: http://'.$row['SITE_URL']);
即使在发送一个有效的网站ID的请求需要从在我与该站点ID相关联DB中列出的结构域。
下面是Apache的,包括一些最新的和计划中的字体定义的扩展选项:
<FilesMatch "\.(ttf|otf|eot|woff|woff2|sfnt|svg)$">
<IfModule mod_headers.c>
SetEnvIf Origin "^http(s)?://(.+\.)?(domainname1|domainname2|domainname3)\.(?:com|net|org)$" AccessControlAllowOrigin=$0$1$2
Header add Access-Control-Allow-Origin %{AccessControlAllowOrigin}e env=AccessControlAllowOrigin
Header set Access-Control-Allow-Credentials true
</IfModule>
</FilesMatch>
和在Django多一个答案。有一个单一的视图允许来自多个域的CORS,这是我的代码:
def my_view(request):
if 'HTTP_ORIGIN' in request.META.keys() and request.META['HTTP_ORIGIN'] in ['http://allowed-unsecure-domain.com', 'https://allowed-secure-domain.com', ...]:
response = my_view_response() # Create your desired response data: JsonResponse, HttpResponse...
# Then add CORS headers for access from delivery
response["Access-Control-Allow-Origin"] = request.META['HTTP_ORIGIN']
response["Access-Control-Allow-Methods"] = "GET" # "GET, POST, PUT, DELETE, OPTIONS, HEAD"
response["Access-Control-Max-Age"] = "1000"
response["Access-Control-Allow-Headers"] = "*"
return response
有关.NET应用程序相当简单的复制/粘贴,我写了这个从Global.asax文件中启用CORS。此代码遵循目前接受的答案提出的意见,反映无论起源早在请求到给出响应。这有效地实现了“*”不使用它。这样做的原因是,它使多个其他CORS功能,包括与“withCredentials”属性设置为“真”发送AJAX的XMLHttpRequest的能力。
void Application_BeginRequest(object sender, EventArgs e)
{
if (Request.HttpMethod == "OPTIONS")
{
Response.AddHeader("Access-Control-Allow-Methods", "GET, POST");
Response.AddHeader("Access-Control-Allow-Headers", "Content-Type, Accept");
Response.AddHeader("Access-Control-Max-Age", "1728000");
Response.End();
}
else
{
Response.AddHeader("Access-Control-Allow-Credentials", "true");
if (Request.Headers["Origin"] != null)
Response.AddHeader("Access-Control-Allow-Origin" , Request.Headers["Origin"]);
else
Response.AddHeader("Access-Control-Allow-Origin" , "*");
}
}
要便于ASMX服务的多个域接入,我在global.asax文件创建这样的功能:
protected void Application_BeginRequest(object sender, EventArgs e)
{
string CORSServices = "/account.asmx|/account2.asmx";
if (CORSServices.IndexOf(HttpContext.Current.Request.Url.AbsolutePath) > -1)
{
string allowedDomains = "http://xxx.yyy.example|http://aaa.bbb.example";
if(allowedDomains.IndexOf(HttpContext.Current.Request.Headers["Origin"]) > -1)
HttpContext.Current.Response.AddHeader("Access-Control-Allow-Origin", HttpContext.Current.Request.Headers["Origin"]);
if(HttpContext.Current.Request.HttpMethod == "OPTIONS")
HttpContext.Current.Response.End();
}
}
这允许CORS处理OPTIONS
动词也
匹配子域PHP的代码示例。
if( preg_match("/http:\/\/(.*?)\.yourdomain.example/", $_SERVER['HTTP_ORIGIN'], $matches )) {
$theMatch = $matches[0];
header('Access-Control-Allow-Origin: ' . $theMatch);
}
一个更灵活的方法是使用Apache 2.4的表达式。您可以对阵域,路径和几乎所有其他的请求变量。虽然响应*
所有,接收响应所述唯一的请求者是无论如何符合要求的那些。
<IfModule mod_headers.c>
<If "%{HTTP:Host} =~ /\\bcdndomain\\.example$/i && %{HTTP:Origin} =~ /\\bmaindomain\\.example$/i">
Header set Access-Control-Allow-Origin "*"
</If>
</IfModule>
Google 的支持答复 通过 SSL 投放广告 和 RFC 本身的语法 似乎表明您可以用空格分隔 URL。不确定不同浏览器对此的支持程度如何。
如果你尝试这么多的代码示例和我一样,使其工作使用CORS,值得一提的是,你必须先清除缓存尝试,如果它的实际工作,类同的问题时,旧图像仍然存在一样,即使它在服务器上删除(因为它仍然保存在高速缓存)。
例如<大骨节病> CTRL + SHIFT + DEL 骨节病>谷歌浏览器,清除缓存。
这个使用此代码帮我想很多纯.htaccess
解决方案之后,这似乎是唯一一个工作(至少对我来说):
Header add Access-Control-Allow-Origin "http://google.com"
Header add Access-Control-Allow-Headers "authorization, origin, user-token, x-requested-with, content-type"
Header add Access-Control-Allow-Methods "PUT, GET, POST, DELETE, OPTIONS"
<FilesMatch "\.(ttf|otf|eot|woff)$">
<IfModule mod_headers.c>
SetEnvIf Origin "http(s)?://(www\.)?(google.com|staging.google.com|development.google.com|otherdomain.com|dev02.otherdomain.net)$" AccessControlAllowOrigin=$0
Header add Access-Control-Allow-Origin %{AccessControlAllowOrigin}e env=AccessControlAllowOrigin
</IfModule>
</FilesMatch>
另外请注意,它被广为流传,许多解决方案,说你必须键入Header set ...
但Header add ...
。希望这有助于有好几个小时一样烦恼的人现在喜欢我。
下面的答案是特定于C#,但概念应适用于所有的不同的平台。
要允许从Web API跨源请求,您需要允许选项请求您的应用程序并添加下面的注释,在控制器级别。
[EnableCors(UrlString,接头,方法)] 现在的来历,可以通过仅s字符串。因此,如果你想通过在请求多于一个的URL将它作为逗号分隔值。
UrlString =“ HTTPS://a.hello.com,https: //b.hello.com “
只有一个单一的原点可以为访问控制允许来源头中指定。但是你可以根据用户的要求原点设置你的回应。另外不要忘记设置Vary头部。在PHP我将执行以下操作:
/**
* Enable CORS for the passed origins.
* Adds the Access-Control-Allow-Origin header to the response with the origin that matched the one in the request.
* @param array $origins
* @return string|null returns the matched origin or null
*/
function allowOrigins($origins)
{
$val = $_SERVER['HTTP_ORIGIN'] ?? null;
if (in_array($val, $origins, true)) {
header('Access-Control-Allow-Origin: '.$val);
header('Vary: Origin');
return $val;
}
return null;
}
if (allowOrigins(['http://localhost', 'https://localhost'])) {
echo your response here, e.g. token
}
我们也可以设置在此对Asp.net应用Global.asax文件。
protected void Application_BeginRequest(object sender, EventArgs e)
{
// enable CORS
HttpContext.Current.Response.AddHeader("Access-Control-Allow-Origin", "https://www.youtube.com");
}
答案似乎是使用头多于一次。即,而不是发送
Access-Control-Allow-Origin: http://domain1.example, http://domain2.example, http://domain3.example
发送
Access-Control-Allow-Origin: http://domain1.example
Access-Control-Allow-Origin: http://domain2.example
Access-Control-Allow-Origin: http://domain3.example
在Apache的,则可以使用httpd.conf
和该语法在<VirtualHost>
.htaccess
部或mod_headers
文件做到这一点:
Header add Access-Control-Allow-Origin "http://domain1.example"
Header add Access-Control-Allow-Origin "http://domain2.example"
Header add Access-Control-Allow-Origin "http://domain3.example"
在技巧是使用add
而非append
作为第一个参数。