HTTPQUERY
English

Access-Control-Allow-Origin

用法

注意

CORS(跨源资源共享)是一种浏览器机制,它会阻止网页读取由不同源提供的响应,除非服务器显式许可访问。浏览器会在跨源请求上自动设置 Origin 头。JavaScript 无法修改 Origin 头。

每个 CORS 响应都包含 Access-Control-Allow-Origin,用于告诉浏览器来自特定源的前端代码是否被允许读取响应。如果没有匹配的值,浏览器会阻止响应到达 JavaScript。

选择允许访问的服务器有三种选择:通配符、明确的源,或 null。大多数生产环境的 API 会通过将传入的 Origin 请求头与允许列表比对来动态选择源。当源匹配时,服务器将该值回显回去。由于响应会随请求而变化,因此需要 Vary: Origin 头,以便缓存为每个源分别存储副本。

什么会触发 CORS

任何对不同源的 fetch() 或 XMLHttpRequest 都会触发 CORS 强制检查。通过 @font-face 加载字体、WebGL 纹理,以及对跨源图片使用 canvas.drawImage() 也会触发 CORS 检查。携带自定义头、使用 PUT、DELETE、PATCH 等非简单方法,或带有 application/json Content-Type 的请求,会在发送实际请求之前先触发一个预检 OPTIONS 请求。标准的导航行为(例如点击链接或在浏览器中加载页面)不会触发 CORS。

*(通配符)

允许任意源读取响应。通配符仅对不带凭据的请求有效。

Access-Control-Allow-Origin: *

注意

通配符与带凭据的请求不兼容。当 Access-Control-Allow-Credentials 为 true 时,服务器必须返回一个明确的源。

明确的源

一个由方案、主机名以及可选端口组成的单一源值。这是限定于已知调用方的 API 的标准做法。

Access-Control-Allow-Origin: https://example.com

每个响应只允许一个源。支持多个源的服务器会检查 Origin 请求头,并回复匹配到的值,同时在响应中加入 Vary: Origin。

null

表示一个不透明或涉及隐私的源。某些沙箱化文档和本地文件 URL 会以 null 作为其源发送。

Access-Control-Allow-Origin: null

注意

不建议以 null 作答。来自沙箱化 iframe 的恶意文档同样携带 null 源,使得该值很容易被伪造。

示例

服务器动态镜像请求方的源,并包含一个 Vary 头以保证正确的缓存行为。

Access-Control-Allow-Origin: https://example.com
Vary: Origin

一个向任意调用方提供静态资源的公共 CDN 使用通配符。

Access-Control-Allow-Origin: *

一个带凭据的跨源响应将明确的源与凭据头配对使用。

Access-Control-Allow-Origin: https://dashboard.example.re
Access-Control-Allow-Credentials: true
Vary: Origin

故障排查

当浏览器无法将响应的源与发起请求的页面匹配时,跨源请求会失败。

控制台显示”No ‘Access-Control-Allow-Origin’ header is present on the requested resource.”。服务器根本没有包含该头。请确认服务端的 CORS 配置应用到了特定的路由和 HTTP 方法。在 nginx 中,确认 add_header 指令位于正确的 location 块内。在 Apache 中,确认 Header set 位于匹配的 内。使用 curl 测试,以将问题与浏览器行为区分开来:curl -v -H “Origin: https://example.comhttps://api.example.re/data

通配符 * 在带凭据的请求中不起作用。浏览器会拒绝将 Access-Control-Allow-Origin: * 与 Access-Control-Allow-Credentials: true 配对的响应。修复方法是读取传入的 Origin 头,对照允许列表校验其值,并将匹配到的源回显回去。在响应中加入 Vary: Origin,以便缓存为每个源分别存储副本。

未经校验的源反射。不检查允许列表就原样回显 Origin 请求头,会使 API 向任意域名敞开。攻击者会利用这一点,通过他们控制的页面窃取数据。在反射之前,务必将传入的源与一份受信任的值列表进行比对。

CDN 缓存了带有错误源的响应。当服务器返回动态源值却省略了 Vary: Origin 时,CDN 会存储第一个源的值,并对之后每个源都提供相同的缓存响应。请在每个反射动态源的响应上加入 Vary: Origin。在 Cloudflare 中,使用 CORS 托管转换时会自动处理这一点。在其他 CDN 中,请确认源是缓存键的一部分。

预检成功但实际请求失败。OPTIONS 响应包含了 CORS 头,但后续的 GET、POST 或 PUT 响应却没有。许多服务器框架会将 OPTIONS 与其他方法分开处理。请确保 CORS 头被添加到所有类型的响应中,而不仅仅是预检响应。在 Express 中,将 CORS 中间件放在路由处理器之前,使每个响应都经过该中间件。

用 curl 调试显示头正确,但浏览器仍然阻止。打开 DevTools,进入 Network 标签,检查浏览器实际收到的响应头。代理、负载均衡器或 CDN 边缘规则有时会在源服务器与浏览器之间剥离或覆盖 CORS 头。将 curl 的输出与 DevTools 的输出对比,找出移除该头的那一层。