← 返回题目列表

同源策略和 CORS 跨域是什么?

高频 中等 第 7 / 30 题 更新于 2026/07/28
浏览器同源策略CORS跨域

简化版

同源策略是浏览器的安全机制,协议、域名、端口都相同才算同源。不同源的脚本读取响应会受限制。CORS 是服务器通过响应头允许指定来源访问资源的机制,常见头包括 Access-Control-Allow-OriginAccess-Control-Allow-MethodsAccess-Control-Allow-Headers

详细版

同源策略限制的是浏览器环境中的跨源读取,目的是防止恶意网站读取用户在其他站点的敏感数据。

跨域不是请求一定发不出去,而是浏览器不允许前端 JS 读取不被授权的响应。

CORS 的核心是服务端声明允许谁访问。简单请求会直接发送,浏览器检查响应头;复杂请求会先发送 OPTIONS 预检请求,确认允许后再发送真实请求。

开发环境也常用代理解决跨域,但生产环境根本方案仍然是服务端正确配置 CORS。

完整版教学

一、什么是同源

同源要求三者都相同:

  • 协议相同,例如 https
  • 域名相同,例如 example.com
  • 端口相同,例如 443

只要有一个不同,就属于跨源。

同源策略保护的是用户数据。例如用户登录了银行网站,如果没有同源策略,恶意网站就可能用用户浏览器身份请求银行数据并读取结果。

二、CORS 的工作方式

CORS 的全称是跨源资源共享。它不是前端单方面能解决的问题,而是浏览器和服务器共同遵守的协议。

服务器返回:

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

浏览器看到当前页面来源被允许,才把响应交给前端 JS。

如果请求包含自定义头、非简单方法或特殊 content-type,浏览器会先发 OPTIONS 预检请求。

如果跨域请求要携带 cookie,需要前端设置 credentials,服务端也要允许凭证。

同时 Access-Control-Allow-Origin 不能简单写 *,必须指定明确来源。

这也是很多登录态跨域问题的根源:请求发了,接口也返回了,但浏览器因为 CORS 规则不把响应交给 JS。

四、面试追问与工程落地

面试官常问:“JSONP 为什么能跨域?”

因为同源策略不限制 <script> 加载跨域脚本。JSONP 利用脚本标签加载一段函数调用。但它只支持 GET,安全性和错误处理都比较弱,现代项目更推荐 CORS。

工程中,开发代理只是本地绕过浏览器跨域限制的便利方案。上线后仍然需要后端网关、API 服务或 CDN 正确配置跨域响应头。

五、简单请求、预检与凭证矩阵

“简单请求”不是不受 CORS 管理,而是浏览器可直接发送实际请求,再检查响应是否允许脚本读取。非简单方法、非 safelisted 请求头或特定 Content-Type 会先发不带普通请求凭证的 OPTIONS 预检,询问服务端允许的方法和头。

场景前端 credentials服务端允许来源结果
公共无凭证 APIomit/默认适用值*可读取
跨源 Cookieinclude明确 Origin + Allow-Credentials可读取
跨源 Cookieinclude*浏览器阻止读取
非允许来源任意无匹配 ACAO浏览器阻止读取
Access-Control-Allow-Origin: https://app.example
Access-Control-Allow-Credentials: true
Vary: Origin

若服务端按白名单动态回显 Origin,必须真实校验而不是原样反射,并配 Vary: Origin 防共享缓存串用响应。预检结果可用 Access-Control-Max-Age 缓存,但浏览器有自己的上限;缓存 600 秒意味着同类请求在 10 分钟内可能免去重复 OPTIONS,不代表实际请求被缓存。

六、CORS、CSRF 与跨源能力边界

同源策略主要限制跨源读取和脚本交互,并不禁止所有跨源资源嵌入或请求。表单、图片、链接等可发起部分跨站请求,所以“攻击者读不到响应”不等于“状态改变不会发生”;CORS 不是 CSRF 防护,修改类接口仍要 SameSite、CSRF token 和 Origin 校验。

反向代理把浏览器看到的 API 变成同源,可以消除前端 CORS 流程,但代理仍需安全地认证上游、过滤头和限制目标地址。开发服务器代理只是本地拓扑,不能解释成“前端修好了服务端跨域”。

JSONP 利用 classic script 可跨源加载并执行,只支持 GET 风格且把第三方响应当代码执行,风险和错误语义都弱。postMessage 适合窗口/iframe 跨源通信,但接收端必须检查 event.origin,发送时避免把 targetOrigin 随意写成 *

安全心法:CORS 决定“哪个 Origin 的脚本能读响应”,CSRF 防护决定“跨站请求能不能以用户身份改变状态”,两者不能互相替代。

七、常见误区与追问

  • 误区:跨域请求一定不会发送到服务器。 简单请求通常先发送,只是响应不满足 CORS 时不会交给脚本读取。
  • 误区:Access-Control-Allow-Origin: * 可以和 Cookie 凭证一起使用。 凭证请求要求明确来源,并配 Access-Control-Allow-Credentials: true
  • 误区:配置 CORS 后就不会遭受 CSRF。 表单等请求不依赖 CORS 读取权限,状态变更仍要专门的 CSRF 防护。
  • 追问:哪些变化常触发预检? 非简单方法、自定义头或不在 safelist 的 Content-Type 等会让浏览器先发 OPTIONS。
  • 追问:预检请求会带业务 Cookie 吗? 按 CORS/Fetch 模型,预检本身不带普通请求凭证,实际凭证请求由双方许可决定。
  • 追问:为什么动态 Origin 响应要加 Vary: Origin 共享缓存需要按 Origin 区分响应,否则可能把允许 A 的头复用给 B。
  • 追问:如何排查“Network 200 但 JS 报 CORS”? 检查实际/预检响应头、重定向、credentials、Origin 精确匹配和控制台错误,而不只看状态码。

八、加强记忆

同源用 scheme、host、port 三元组判断;CORS 是浏览器依据服务端响应头决定能否把跨源响应交给脚本。简单请求直接发后检查,非简单请求先预检;带凭证时客户端 include、明确允许来源和 Allow-Credentials 必须同时成立。最后牢记 CORS 管读取,不负责阻止 CSRF 状态变更。