术语表

CORS 是什么 — 原理,以及配置错误(CORS misconfiguration)会引发什么

CORS(跨源资源共享)是浏览器控制其他源的 JavaScript 能否读取 API 响应的机制。配置过宽会让第三方网站读取已登录用户的数据。讲解原理与白名单、不反射 Origin 等安全配置。

发布于 2026-06-11 更新于 2026-10-06 3 分钟阅读
本页目录

加上 Access-Control-Allow-Origin 之后 API 能用了,并不代表它就安全。CORS 不是加上一次就不用再管的东西,关键在于把许可的对象收紧。本文讲解它的原理和安全的配置方法(不会写出攻击步骤)。

先讲原理

浏览器有一条同源策略:其他源的 JS 不能擅自读取其他网站的响应。CORS 就是用来把这条规则的例外只对服务器明确许可的对象打开的机制。

源(origin)是协议(https)、主机名和端口的组合。https://example.com 与 https://api.example.com 主机不同,所以是不同的源;http://example.com 与 https://example.com 协议不同,也是不同的源。

响应头含义
Access-Control-Allow-Origin允许哪个源读取响应
Access-Control-Allow-Credentials是否允许带 Cookie 等认证信息的通信
Access-Control-Allow-Methods / -Headers允许的 HTTP 方法/头

关键在于,CORS 是属于「放宽限制」那一侧的机制。放宽的方式一旦出错,本不该被读取的数据就会被第三方读到。

还有一点很重要:CORS 阻止的是 JavaScript 读取响应。简单请求即使没有 CORS 许可,也会到达服务器并被处理。对于使用自定义请求头等情况,浏览器会先用 OPTIONS 请求确认(预检),不被允许时就不发送真正的请求。

与相似机制的区别

CORS 常被与名称相近的机制或密切相关的漏洞混淆。

术语决定什么由谁执行
同源策略其他源不能读取响应(浏览器的默认行为)浏览器
CORS作为上述规则的例外,允许哪些源读取服务器声明,浏览器执行
CSRF让用户处于登录状态的浏览器发送非本意请求的攻击用 CSRF 令牌和 SameSite 防御
CSP自家页面可以加载哪些脚本、连接哪些地址服务器声明,浏览器执行

CORS 关心的是「响应能否被读取」,CSRF 关心的是「能否以用户的名义发送请求」。收紧 CORS 并不能防止 CSRF。

哪些配置是危险的

危险的配置(容易犯)

  • 把请求的 Origin 原样反射回去并予以许可
  • Access-Control-Allow-Origin: * + 同时允许认证信息
  • 把不必要的 API 也大范围地对其他源开放

安全的配置

  • 白名单(只放可信任的固定源)
  • 其他一律默认拒绝
  • 带认证信息时不用 *,而指定具体的源
攻击者网站的 JS 向你的 API 发起请求(用户处于登录状态)
↓ 服务器不加判断地许可了 Origin(配置错误)
浏览器允许读取响应=个人信息/令牌被交到攻击者网站手里
配置太宽时,攻击者网站的 JS 就能借用用户的登录状态读取到 API 的响应。

配置错误通常是怎样产生的

大多数配置错误,源于想让 CORS 错误消失。典型的过程如下:

  1. 前端带着 Cookie 调用 API 时出现 CORS 错误
  2. 加上 Access-Control-Allow-Origin: *。但对于带认证信息的请求,浏览器不允许页面读取 * 的响应,所以错误依然存在
  3. 改成把收到的 Origin 原样返回,错误消失了。与此同时,任何网站都能读取已登录的响应

即使使用了白名单,比对方式草率也会导致同样的结果。

  • 按「以 example.com 结尾」比对,会把 evil-example.com 这样的其他域名也放进来
  • 按「以 https://example.com 开头」比对,会把 https://example.com.evil.net 也放进来
  • 为了开发方便而允许 null 源,其他网站也能制造出 null 源来读取响应

请对整个源(协议、主机和端口)做完全一致的比对。

安全配置的基本原则

1

采用白名单方式(最重要)

只许可事先确定的可信任的源,其他一律拒绝(默认拒绝)。不要「先全部许可了再说」。
2

不要不加判断地反射 Origin

不要把请求里的 Origin 原样 echo 到 Access-Control-Allow-Origin。只有与白名单比对一致时才返回。由于返回值会随请求变化,还要同时发送 Vary: Origin,避免缓存混用响应。
3

带认证信息时不要用 *

带 Cookie 等的通信中,不要把 Access-Control-Allow-Origin: * 与 Allow-Credentials: true 同时使用。要指定具体的源。
4

把开放范围降到最小

只把确实需要对其他源公开的端点作为对象。不要大范围开放。* 只用于不需要登录的公开数据。

如何检查自己的网站

向自家 API 发送一个声称来自其他源的请求,查看响应头。请只对自己管理的 API 这样做。

# 声称来自未被允许的源,只查看响应头
curl -s -o /dev/null -D - -H "Origin: https://example.com" https://your-api.example/ | grep -i "^access-control"
  • 如果返回 Access-Control-Allow-Origin: https://example.com,说明 API 在反射 Origin。请加上白名单比对
  • 如果同时出现 Access-Control-Allow-Origin: * 和 Access-Control-Allow-Credentials: true,请重新审视配置
  • 如果什么都没有返回,或只返回自家前端的源,就没有问题

再用 Origin: null 重复同样的检查。对于已验证所有权的网站,网站安全诊断会一并检查 Origin 反射和认证信息相关的配置。其他安全响应头可以用安全响应头诊断确认。

本站的观点:CORS 不是「防守」,而是「放宽方式」。要收紧放宽的对象

一个常见的误解是「加上 CORS 头就安全了」。恰恰相反,CORS 是属于「放宽」浏览器限制那一侧的机制。所以关键与其说是「怎么加」,不如说是「把对谁、开放到什么程度收到最小」。

本站建议把可以被外部读取的数据和不可以的数据区分开,采取默认拒绝、只用白名单打开例外的方针。另外,让「响应会被读取」这一前提整个崩塌的 XSS,以及瞄准状态变更的 CSRF 是另一类漏洞,所以单靠 CORS 并不能守住全部。

出处(一手资料)

  • MDN Web Docs, "Cross-Origin Resource Sharing (CORS)" — developer.mozilla.org(带认证信息的请求不能用 *、预检的触发条件、Vary: Origin)
  • WHATWG Fetch Standard, "CORS protocol" — fetch.spec.whatwg.org
  • OWASP HTML5 Security Cheat Sheet — cheatsheetseries.owasp.org(只允许可信任的域名;不要未经检查就返回 Origin 头)
  • PortSwigger Web Security Academy, "Cross-origin resource sharing (CORS)" — portswigger.net(白名单比对错误、null 源、CORS 不是 CSRF 防护)
  • MITRE CWE-942: Permissive Cross-domain Policy with Untrusted Domains — cwe.mitre.org

延伸阅读

分类编号

CWE 对导致漏洞的弱点类型进行分类,MITRE ATT&CK 对攻击者的技术进行分类。两者均由 MITRE 维护,广泛用于标注漏洞信息和检测规则。

CWE™: Copyright © 2006–2026, The MITRE Corporation. CWE is a trademark of The MITRE Corporation. The MITRE Corporation hereby grants you a non-exclusive, royalty-free license to use CWE for research, development, and commercial purposes. Any copy you make for such purposes is authorized on the condition that you reproduce MITRE’s copyright designation and this license in any such copy. CWE Terms of Use

FAQ

QCORS 是干什么用的机制?
A

浏览器有一条「同源策略」:另一个源(网站)的 JavaScript 不能擅自读取其他网站的响应。CORS(Cross-Origin Resource Sharing)就是用来把这条规则的例外「只对服务器明确许可的对象」打开的机制。它通过 Access-Control-Allow-Origin 等响应头,声明允许哪些源读取响应。

QCORS 配置错误会引发什么?
A

如果许可放得太宽,攻击者网站的 JavaScript 就可能读取到用户已登录的 API 响应。典型例子是:把请求的 Origin 原样反射回去并予以许可,或者把 Access-Control-Allow-Origin 设为 * 的同时还允许认证信息(Cookie 等)。结果就是个人信息或令牌可能被交到第三方网站手里。

Q安全配置的基本原则是什么?
A

就是「白名单方式」。只许可事先确定的、可信任的源,其他一律拒绝(默认拒绝)。不要不加判断地反射请求里的 Origin。在带认证信息的通信中,Access-Control-Allow-Origin 不要用 *,而要指定具体的源。最根本的是,只把确实需要对其他源公开的端点作为对象。

Q出现了 CORS 错误,把 Access-Control-Allow-Origin 设成 * 可以吗?
A

如果是不需要登录、只返回公开数据的 API,用 * 没有问题。但对于带 Cookie 等认证信息的请求,浏览器不允许页面读取 * 的响应,所以错误依然存在。如果这时改成把收到的 Origin 原样返回,任何网站都能读取响应。正确的做法是把自家前端的源写进白名单,只在完全一致时才返回它。

Q配置了 CORS 就能防止 CSRF 吗?
A

不能。CORS 控制的是「响应能否被读取」,而不是「请求能否被发送」。简单请求(例如与表单提交形式相同的 POST)即使没有 CORS 许可也会到达服务器。CSRF 要用 CSRF 令牌和 Cookie 的 SameSite 属性来防御。

Q预检请求(preflight)是什么?
A

在发送真正的请求之前,浏览器先用 OPTIONS 请求询问服务器是否允许该方法和请求头。使用自定义请求头、以 application/json 发送的 POST、PUT、DELETE 等情况会触发预检。如果不被允许,真正的请求就不会发送。只使用 GET、HEAD,或只使用允许的请求头和内容类型的 POST 等简单请求,不会触发预检。