在 Access-Control-Allow-Origin 中使用通配符作为子域

Posted

技术标签:

【中文标题】在 Access-Control-Allow-Origin 中使用通配符作为子域【英文标题】:Using wildcard for subdomain in Access-Control-Allow-Origin 【发布时间】:2017-03-05 20:54:30 【问题描述】:

我在我的网站上使用 Express 并使用凭据 xhr。我想从http://admin.example.comhttp://service1.example.comhttp://example.com 请求,这是我在快递服务器中的Access-Control-Allow-Origin 部分:

// CORS
app.use((req, res, next) => 
    res.setHeader('Access-Control-Allow-Origin', 'http://*.example.com');
    res.setHeader('Access-Control-Allow-Headers', 'X-Requested-With,Content-Type');
    res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS, PUT, DELETE');
    next();
);

但是当我尝试从 http://admin.example.comhttp://example.com 的凭证 xhr 时,它失败了:

Fetch API 无法加载 http://example.com/api/v1/authentication/signin。 对预检请求的响应未通过访问控制检查: 'Access-Control-Allow-Origin' 标头有一个值 'http://*.example.com' 这不等于提供的来源。起源 'http://admin.example.com' 因此不允许访问。有 服务器发送带有有效值的标头,或者,如果响应不透明 满足您的需求,将请求的模式设置为“no-cors”以获取 禁用 CORS 的资源。

看起来是因为浏览器不明白*.example.com到底是什么意思,拒绝请求。

我想从这些域中请求:

example.com admin.example.com service1.example.com service2.example.com [任何东西].example.com

我正在为 XHR 使用 Fetch API,并设置 credentials: true。有什么我错过的吗?任何建议都会非常感激。

【问题讨论】:

【参考方案1】:

我同意 Derric 的评论。另一件事是原始标头可以被欺骗,所以这不是一个安全的解决方案。

app.use(function (req, res, next) 
  if (req.headers.origin.endsWith('example.com')) 
    res.setHeader('Access-Control-Allow-Origin', 'http://' + req.headers.origin)
    res.setHeader('Access-Control-Allow-Headers', 'X-Requested-With,Content-Type')
    res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS, PUT, DELETE')
  
  next()
)

【讨论】:

【参考方案2】:

首先,IIRC;快递文件明确要求您不要使用 中间件的 lambda 表达式。

谈到 CORS 问题,通配符子域在上下文中无效。该支持是最近添加的(在 May '16 中),直到那时,the CORS header must be an exact match of the domain name。

但是,您可以处理您的 req.hostname 值并将其添加到响应标头中:

// CORS
app.use(function (req, res, next) 
    if (req.hostname.endsWith('example.com')) 
        res.setHeader('Access-Control-Allow-Origin', 'http://' + req.hostname)
        res.setHeader('Access-Control-Allow-Headers', 'X-Requested-With,Content-Type')
        res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS, PUT, DELETE')
    
    next()
)

【讨论】:

我会调整它以不使用主机名,而您应该使用 Origin 标头。在您的情况下,主机名将是 example.com,但来源将是 admin.example.com。 Origin 需要匹配确切的协议和域(如果是非标准端口,还需要匹配端口)。更多信息:moesif.com/blog/technical/cors/…【参考方案3】:

在此处添加另一个小调整。我们还应该考虑“协议”:

app.use(function (req, res, next) 
  if (req.headers.origin.endsWith('example.com')) 
    res.setHeader('Access-Control-Allow-Origin', req.protocol + '://' + req.headers.origin)
    res.setHeader('Access-Control-Allow-Headers', 'X-Requested-With,Content-Type')
    res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS, PUT, DELETE')
  
  next()
)

【讨论】:

以上是关于在 Access-Control-Allow-Origin 中使用通配符作为子域的主要内容,如果未能解决你的问题,请参考以下文章

为龙卷风中的所有请求设置标头

为啥 axios get 方法请求发送两次?

将 JSON 数据发布到返回状态代码 0 的 API

使用 res.header express node js 的数组的正确方法是啥

接收不到shopify webhook 发送post请求

CSRF 保护如何为我提供比 CORS 控制更高的安全性(前端/后端位于两个不同的域)?