CORS 配置有哪些安全注意点?
简化版
CORS 是服务端授权浏览器跨源读取响应的机制。安全上不能随意允许所有来源,尤其携带 Cookie 时不能使用 *。应使用明确白名单、限制方法和请求头、正确处理预检请求,并且不要把 CORS 当作接口鉴权。
详细版
常见风险配置:
Access-Control-Allow-Origin: *过于宽泛。- 携带凭证时动态反射任意 Origin。
- 允许过多方法和请求头。
- 预检请求不校验业务来源。
- 认为没有 CORS 就能保护接口。
正确做法:
- 使用可信 Origin 白名单。
- 携带 Cookie 时明确返回具体 Origin。
- 配置
Access-Control-Allow-Credentials要谨慎。 - 限制允许的方法和请求头。
- 接口必须做服务端鉴权。
CORS 解决的是浏览器能否把响应交给 JS,不是服务端权限控制。
完整版教学
一、CORS 的安全边界
CORS 是浏览器安全模型的一部分。它决定跨源页面是否能读取响应内容。
但请求本身可能已经到达服务器。因此接口不能依赖 CORS 来判断请求是否可信。攻击者可以用服务器脚本、curl、Postman 直接请求接口。
二、为什么不能随便反射 Origin
有些后端会把请求头里的 Origin 原样返回:
Access-Control-Allow-Origin: <请求里的 Origin>
如果不校验白名单,就等于允许任何网站读取响应。对于携带凭证的接口,这非常危险。
三、携带凭证的特殊规则
跨域请求如果要带 Cookie,需要前端设置 credentials,服务端返回:
Access-Control-Allow-Credentials: true
这时 Access-Control-Allow-Origin 不能是 *,必须是明确来源。否则浏览器会拒绝。
四、面试追问与工程落地
面试官可能问:“CORS 报错是不是前端改一下就能解决?”
多数情况下不是。CORS 授权在服务端响应头中,前端只能按规则发请求。开发环境代理可以绕过浏览器跨域,但生产环境必须由服务端或网关正确配置。
工程中 API 网关应集中管理 CORS 白名单,避免每个服务随意配置。
五、白名单、凭证和缓存要一起设计
动态 CORS 最容易漏掉缓存维度。若服务端根据请求 Origin 返回不同的 Access-Control-Allow-Origin,共享缓存必须知道响应随 Origin 变化:
Access-Control-Allow-Origin: https://app.example.com
Access-Control-Allow-Credentials: true
Vary: Origin
| 配置 | 浏览器读取结果 | 风险判断 |
|---|---|---|
Allow-Origin: *,无凭证 | 任意来源可读 | 只适合公开数据 |
| 精确 Origin + 凭证 | 白名单来源可读 | 登录态接口常用 |
| 反射任意 Origin + 凭证 | 任意网站可读用户数据 | 高危错误 |
| 多个 Origin 写在一个头里 | 通常无效 | 应按白名单返回单个来源 |
白名单应把 URL 解析后精确比较 scheme、host、port,不能用 endsWith('example.com'),否则 evil-example.com 也可能通过。还要明确是否接受 Origin: null;沙箱 iframe、本地文件等可能产生 null 来源,默认不应信任。
CORS 的核心问题是“浏览器是否把响应交给调用页面”,不是“请求有没有身份、能不能执行操作”。
六、用数字和攻击路径验证配置
假设接口响应 20KB,前端每分钟调用 30 次,若每次 JSON 请求都先预检,就会多 30 个 OPTIONS。设置合适的 Access-Control-Max-Age 能减少往返,但浏览器会有自己的上限,策略变更也要考虑旧预检缓存窗口。
安全测试要覆盖三类客户端:允许来源的浏览器请求应成功;恶意来源的浏览器 JS 应拿不到响应;curl 即使不带 Origin 仍可能请求成功,但必须因缺少身份或权限而被业务拒绝。第三项正好证明 CORS 不是鉴权。
浏览器页面 → CORS 检查 → 决定 JS 能否读取
非浏览器客户端 ─────────→ 服务端鉴权与授权
简单跨源请求可能不预检并直接到达服务端,所以不能把“预检失败”当作 CSRF 防护。状态修改接口仍需 SameSite、CSRF Token、Origin/Fetch Metadata 校验等独立措施。
七、常见误区与追问
- 误区:没有 CORS 头,攻击者就无法请求接口。 非浏览器客户端不受 CORS 限制,部分浏览器请求也会先到达服务端。
- 误区:携带 Cookie 时可以返回
Access-Control-Allow-Origin: *。 凭证模式要求明确来源,星号响应不会向前端暴露。 - 误区:把请求 Origin 原样返回就是通用方案。 未经白名单验证的反射会把任意恶意站点变成受信来源。
- 追问:动态 Origin 为什么要加
Vary: Origin? 防止共享缓存把给 A 来源的响应头错误复用给 B 来源。 - 追问:为什么 Postman 正常而浏览器报错? Postman 不执行浏览器 CORS 模型,服务端响应可能正常但缺少跨源授权头。
- 追问:允许 CORS 是否等于允许 CSRF? 两者不同;CORS管读取,CSRF关注借用户凭证执行状态变更。
- 追问:白名单能否只匹配域名后缀? 不应,应解析并精确比较协议、主机和端口,避免后缀绕过。
八、加强记忆
- 作用域:CORS 是浏览器跨源读取授权,不是服务端身份认证。
- 凭证规则:Cookie 场景返回精确 Origin,并设置 Allow-Credentials。
- 白名单:解析 origin 三元组精确匹配,不反射任意输入。
- 缓存:动态响应补
Vary: Origin,预检缓存时间要可控。 - 最小授权:只开放必要方法、请求头和暴露头。
- 测试闭环:合法浏览器、恶意浏览器、非浏览器客户端三类都要测。