CORS 是什么
CORS 是浏览器同源策略下的一套跨域授权协议:当页面向不同源的地址发起请求时,浏览器会先检查服务端有没有明确授权,只有服务端用一组响应头声明允许,浏览器才会把响应交给脚本。因此它是浏览器的安全机制,不是服务端的访问控制——用命令行工具请求同一地址不会被拦截,这也解释了为什么经常出现「命令行能通、页面上通不过」的现象。
基本信息
| 定位 | 浏览器的跨域授权协议,源自同源策略 |
|---|---|
| 同源判定 | 协议、域名、端口三者全部相同才算同源 |
| 核心响应头 | 允许来源、允许方法、允许头部、是否允许凭证 |
| 预检请求 | 非简单请求会先发一次探测请求,服务端需正确响应 |
| 关键约束 | 允许携带凭证时,允许来源不能写成通配 |
典型使用场景
- 前后端分离部署:页面域与接口域不同,需要显式授权
- 多域名共存:主站与子站之间互相调用接口
- 第三方接入:把接口开放给合作方页面直接调用
- 本地开发调试:开发服务器端口与接口端口不同即属跨域
- 自定义请求头:携带令牌或自定义头部会触发预检
带凭证的跨域响应
带凭证的跨域响应
允许来源; 写成具体的页面域 # 携带凭证时不能使用通配
是否允许携带凭证; 设为真 # 与上一行必须同时配置
区分缓存的字段; 值为来源 # 同一地址对不同来源响应不同,必须声明否则缓存会串响应头组怎么读
| 响应头 | 作用与常见错误 |
|---|---|
| 允许来源 | 写通配或动态回显任意来源都是高风险配置 |
| 允许方法 | 预检里声明允许哪些方法,缺少就通不过 |
| 允许头部 | 自定义头部必须列出来,否则预检失败 |
| 是否允许凭证 | 开启时来源必须具体,且客户端也要声明携带凭证 |
| 预检结果缓存时长 | 过短会让预检请求频繁发出,增加延迟 |
| 允许读取的额外响应头 | 不声明时脚本只能读到少数几个基础头部 |
排查要点
- 命令行能通页面不通,优先怀疑跨域配置而不是接口本身
- 端口不同也是跨域,检查时要把协议、域名、端口三者一起比对
- 预检失败时看服务端是否处理了探测方法,很多框架默认不处理
允许来源动态回显任意请求方并同时开启携带凭证,是最典型的跨域配置漏洞:等于对所有站点开放,任何第三方页面都能带着用户凭证读写接口。必须按白名单校验。
预检结果会被浏览器缓存一段时间,调大缓存时长能显著减少探测请求;但改动跨域配置后,用户可能在一段时间内仍使用旧的缓存结果,排障时需要考虑这一点。