什么是同源策略 (Same-Origin Policy)?
同源策略 (Same-Origin Policy, 简称 SOP) 是浏览器最核心、最基本的安全功能。它是浏览器为了防止恶意文档窃取数据而设立的一个安全沙箱机制。
简单来说,同源策略限制了从同一个源加载的文档或脚本如何与来自另一个源的资源进行交互。
以下是关于同源策略的详细解释:
1. 什么是“同源” (Origin)?
如果两个 URL 的 协议 (Protocol)、域名 (Domain/Host) 和 端口 (Port) 都完全相同,那么它们就是“同源”的。只要有任何一项不同,就被认为是“跨域” (Cross-Origin)。
举例说明:
假设当前页面的 URL 是 http://www.example.com/dir/page.html (默认端口 80)
| URL | 结果 | 原因 |
|---|---|---|
http://www.example.com/dir2/other.html |
同源 | 协议、域名、端口均相同 |
http://www.example.com/dir/inner/another.php |
同源 | 路径不同不影响同源判断 |
https://www.example.com/page.html |
跨域 | 协议不同 (https vs http) |
http://en.example.com/page.html |
跨域 | 域名不同 (子域名不同) |
http://example.com/page.html |
跨域 | 域名不同 (主域名 vs www) |
http://v2.www.example.com/page.html |
跨域 | 域名不同 |
http://www.example.com:81/dir/page.html |
跨域 | 端口不同 (81 vs 80) |
2. 同源策略限制了什么?
如果是非同源(跨域),浏览器会限制以下行为:
- 无法读取 Cookie、LocalStorage 和 IndexDB:
- 恶意网站无法读取你在银行网站登录后留下的 Cookie。
- 无法接触 DOM:
- 如果你在网页中用
<iframe>嵌入了不同源的页面,你无法通过 JavaScript 获取该 iframe 中的 HTML 元素或输入框内容。
- 如果你在网页中用
- 限制 AJAX 请求 (XMLHttpRequest / Fetch):
- 这是开发中最常遇到的。浏览器通常允许发送跨域请求,但会拦截响应。也就是说,请求发出去了,服务器也处理并返回了,但浏览器发现是跨域,就不把数据交给你的 JavaScript 代码。
3. 为什么需要同源策略?
如果没有同源策略,互联网将极其危险。
场景举例:
- 你刚刚登录了你的网上银行
bank.com,浏览器保存了你的登录 Cookie。 - 你不小心访问了一个恶意网站
evil.com。 - 如果没有同源策略,
evil.com的网页代码可以向bank.com/api/transfer发送 AJAX 请求。 - 因为浏览器会自动带上
bank.com的 Cookie,银行服务器会认为这是你本人的操作,从而执行转账。 evil.com还可以读取银行页面的响应数据,获取你的余额信息。
有了同源策略,evil.com 无法读取 bank.com 的 Cookie,也无法读取 bank.com 返回的数据,从而保护了你的安全。
4. 同源策略的“例外” (允许的操作)
同源策略并不是禁止所有跨域行为,它主要限制的是脚本对数据的访问。以下嵌入资源的标签通常不受同源策略限制(但不能读内容,只能展示或执行):
<img src="...">:可以加载跨域图片。<link href="...">:可以加载跨域 CSS。<script src="...">:可以加载跨域 JS 脚本(如 CDN 上的 jQuery)。<video>和<audio>:可以加载跨域媒体资源。<iframe>:可以加载跨域页面(但 JS 无法操作其内部 DOM)。
5. 如何解决跨域问题?
在现代 Web 开发中,前后端分离架构很常见(前端在 localhost:8080,后端在 api.server.com),这必然涉及跨域。我们通常使用以下方法来安全地绕过同源策略:
- CORS (Cross-Origin Resource Sharing,跨域资源共享) —— 【最推荐、最标准】
- 这是 W3C 标准。后端服务器在响应头中设置
Access-Control-Allow-Origin等字段,明确告诉浏览器:“我允许这个源的页面访问我的数据”。
- 这是 W3C 标准。后端服务器在响应头中设置
- 反向代理 (Proxy)
- 在开发环境中(如 Vue/React CLI)或生产环境(Nginx),设置一个代理服务器。
- 浏览器请求同源的代理服务器,代理服务器再去请求目标服务器。因为同源策略是浏览器的限制,服务器与服务器之间的通信不受限制。
- JSONP (JSON with Padding)
- 利用
<script>标签不受跨域限制的特性。只能发送 GET 请求,且不安全,现代开发已很少使用。
- 利用
- WebSocket
- WebSocket 协议本身不受同源策略限制,但服务器通常会验证 Origin 头来确保安全。
- postMessage
- 用于解决两个跨域窗口(如 iframe 和父窗口)之间的通信问题。
总结
同源策略是浏览器的一道安全防线,它默认禁止跨域访问数据,以防止恶意攻击(如 CSRF、数据窃取)。开发者在需要跨域交互时,应使用 CORS 等标准手段来显式地开启权限。