人人都会AI编程

同源策略的本质与限制

更新时间:2026-07-11

同源策略(Same-Origin Policy)是浏览器最核心的安全机制,也是前端开发者绕不开的一道坎。它规定了一个源(origin)的脚本只能读取、操作同源文档的资源和数据,而不能随意访问其他源的资源。理解它是理解所有跨域方案的起点。

什么是“同源”

一个“源”由三部分组成:协议(scheme)、域名(host)、端口号(port)。只要这三者完全一致,就属于同源;三者中任何一项不同,就是跨域(跨源)。

典型示例(设当前页面源为 http://www.example.com:80):

| 对比 URL | 是否同源 | 原因 |
|---|---|---|
| http://www.example.com/app | ✅ 同源 | 路径不同不影响源 |
| https://www.example.com | ❌ 跨域 | 协议不同(http vs https) |
| http://example.com | ❌ 跨域 | 域名不同(www 子域也算不同) |
| http://www.example.com:8080 | ❌ 跨域 | 端口不同(80 vs 8080) |
| http://www.example.com/api | ✅ 同源 | 路径不参与源比较 |

特例:IE 浏览器的同源策略不比较端口,而所有现代浏览器都严格执行三要素完全匹配。

本质:浏览器强加的安全契约

同源策略的出发点非常朴素:保护用户数据不被恶意网站窃取或篡改

试想没有同源策略,你访问了一个恶意网站 evil.com,该网站可以通过脚本:

  • 读取你已登录的 bank.com 的页面内容,偷走余额信息
  • bank.com 发送转账请求,带上你的登录态
  • 读取你邮箱中的私密邮件

为了防止这种跨站读取和篡改,浏览器给每个源分配了独立的沙箱,一个源内的脚本无法直接触及另一个源的 DOM、Cookie、存储数据和网络响应内容。同源策略是浏览器安全的基石,其核心原则是:跨域写操作通常允许,跨域读操作严格限制

具体限制了什么

同源策略的限制主要体现在三个层面:

  1. DOM 访问限制

不同源的页面之间无法通过 JavaScript 获取彼此的 DOM。例如,父页面中通过 <iframe> 嵌入了跨域子页面,父页面上的脚本无法读取 iframe.contentWindow.document,会抛出跨域安全错误。

  1. 数据存储隔离

Cookie、localStorage、sessionStorage、IndexedDB 均以源为边界。bank.com 设置的 Cookie 无法被 evil.com 的脚本读取,浏览器也禁止跨源访问存储数据。这保证了用户凭证和本地数据不会泄漏给第三方源。

  1. AJAX 请求响应读取限制

这里有一个常被误解的点:同源策略并不阻止浏览器发起跨域请求,它只禁止前端脚本读取跨域请求的响应。
例如,你可以用 XMLHttpRequestfetchapi.other.com 发送一个 POST 请求,请求成功发出并到达服务器,但浏览器检查到响应来自不同源,会拒绝将响应数据交给你的 JavaScript 代码,直接在控制台报错。这种限制强迫前后端分离的 Web 应用必须使用跨域方案。

哪些行为不受同源策略限制

同源策略并非铁板一块,为了兼顾功能和体验,浏览器为某些资源加载开辟了例外:

  • <script> 标签加载跨域 JS:这是 JSONP 的实现基础,但加载到的脚本会直接在当前源执行,存在安全隐患。
  • <img> 标签加载图片:跨域图片可以正常显示,但无法用 Canvas 读取像素数据(会污染画布)。
  • <link> 标签加载 CSS:跨域样式表可以正常应用,但 CSSOM 的读取受限。
  • <video><audio><iframe> 加载资源:可以跨域加载,但脚本无法直接读取内容。
  • 表单提交<form> 可以直接跨域提交,这是典型的跨域写操作,一直不受限制。
  • <a> 标签导航:用户点击链接可以跳转到任何源,不违反同源策略。

这些例外本质上是“允许跨域引用静态资源,但限制脚本读取敏感数据”的折中方案。

对实际开发的影响

前后端分离成为主流的今天,API 通常部署在不同域名或端口下,跨域问题几乎是每个项目的必考题。深刻理解同源策略后,你会发现所有跨域方案(CORS、JSONP、代理、postMessage 等)都是在遵守或绕过这个安全策略——要么让服务器声明信任特定源(CORS),要么通过服务器中转避开浏览器限制(代理),要么使用不受策略限制的通信通道(postMessage)。这也是 16.4 节后续内容要逐一剖析的重点。