同源策略在前端安全中起什么作用?
简化版
同源策略是浏览器安全基础,限制不同源页面之间读取数据。协议、域名、端口都相同才算同源。它能防止恶意网站读取用户在其他网站的敏感数据,但不阻止所有跨域资源加载。
详细版
同源策略主要限制:
- 不同源脚本读取页面 DOM。
- 不同源 Ajax 读取响应。
- 不同源存储数据隔离。
但有些资源可以跨源加载:
- 图片。
- 脚本。
- CSS。
- iframe。
能加载不代表能读取内容。同源策略的关键是保护数据读取能力。
跨域访问数据需要 CORS、postMessage、代理等受控方案。
完整版教学
一、什么是同源
同源要求协议、域名、端口完全一致。
例如 https://a.com 和 http://a.com 不同源,因为协议不同;https://a.com:443 和 https://a.com:8443 不同源,因为端口不同。
同源策略是浏览器站点隔离的基础。
二、为什么需要同源策略
用户登录了邮箱网站后,又打开一个恶意网站。如果没有同源策略,恶意网站的 JS 可能直接请求邮箱接口并读取邮件内容。
同源策略阻止恶意页面读取其他站点的敏感响应,从根上保护用户数据。
三、同源策略的边界
同源策略不是禁止所有跨源请求。比如 <img> 可以加载跨域图片,<script> 可以加载跨域脚本。
但脚本加载跨源资源也带来风险,所以才有 CSP、SRI 等进一步安全机制。
四、面试追问与工程落地
面试官可能问:“跨域请求到底是发不出去,还是响应拿不到?”
很多情况下请求已经发出,服务器也返回了,但浏览器因为没有 CORS 授权,不把响应交给前端 JS。这个区别很重要,因为服务端仍然可能收到请求。
工程中不能把同源策略当服务端安全边界。接口权限、身份校验仍必须由服务端完成。
五、origin、site 与资源能力不要混淆
origin 是 scheme + host + port,site 通常按可注册域及 scheme 判断;Cookie 的 SameSite 与 DOM/CORS 的 same-origin 不是同一个概念。
| URL A | URL B | 是否同源 | 原因 |
|---|---|---|---|
https://a.example/x | https://a.example/y | 是 | 三元组相同 |
https://a.example | http://a.example | 否 | scheme 不同 |
https://a.example | https://b.example | 否 | host 不同 |
https://a.example | https://a.example:8443 | 否 | port 不同 |
跨源 <script> 能加载且会在当前页面执行,但调用页面通常不能读取跨源 iframe DOM;跨源图片能显示,却不能随意把像素读进 Canvas。浏览器按资源类型和能力分别设限,不是一个“跨域开关”。
记忆钩子:同源策略重点保护“读取和操作能力”;请求能发、资源能显示,不等于调用者能读取内容。
六、受控跨源通信如何设计
接口读取使用 CORS,由资源服务器选择允许的 origin;窗口通信使用 postMessage,发送端指定精确 targetOrigin,接收端同时检查 event.origin、event.source 和消息结构。
window.parent.postMessage({ type: 'PAYMENT_DONE', orderId: 'A123' }, 'https://shop.example')
window.addEventListener('message', event => {
if (event.origin !== 'https://pay.example') return
if (event.data?.type !== 'PAYMENT_DONE') return
// 再校验 orderId 与当前会话
})
若一个页面每秒收到 1000 条恶意消息,只校验 origin 仍可能造成处理压力,因此应先快速拒绝,再做 schema 和业务校验。服务端代理/BFF 可代表服务器请求其他服务,但它不会让浏览器同源策略消失,代理自身还需鉴权、防 SSRF 和限制上游。
遗留 document.domain 会放松子域隔离且限制很多现代能力,不应作为新项目跨域方案。JSONP 只能做 GET 且本质执行第三方脚本,也不适合敏感数据。
七、常见误区与追问
- 误区:跨源请求一定不会发到服务器。 表单、图片和许多 fetch 流程可能已发送,只是响应读取被限制。
- 误区:同一个主域下的所有子域天然同源。 host 不同就是不同 origin,除非使用不推荐的旧式放松机制。
- 误区:
postMessage(..., '*')永远安全。 敏感数据可能被错误窗口接收,应指定精确 targetOrigin。 - 追问:为什么跨域 script 可以执行? script 标签被设计为可跨源加载,执行的是代码而非向调用者暴露源码读取能力。
- 追问:CORS 会关闭同源策略吗? 不会,它是资源服务器对特定跨源读取的受控授权。
- 追问:Cookie 与 localStorage 的隔离是否相同? 不相同;Cookie 还有 Domain/Path/SameSite,Web Storage 主要按 origin 隔离。
- 追问:BFF 为什么能取跨域接口? 同源策略约束浏览器脚本,服务器间请求不受它约束,但必须另做服务端安全控制。
八、加强记忆
- 同源三元组:scheme、host、port 必须全部相同。
- 核心保护:限制跨源读取 DOM、响应和存储,而非禁止一切网络动作。
- 分类型判断:图片、脚本、iframe、fetch 的能力边界不同。
- 接口授权:用 CORS 精确开放来源,不依赖浏览器替服务端鉴权。
- 窗口通信:postMessage 双向校验 origin/source、消息 schema 和业务状态。
- 拒绝旧捷径:新项目不靠 document.domain、敏感 JSONP 或任意
*。