同源策略
同源策略是浏览器的一种安全机制,用于限制不同源(Origin)之间的交互。它是浏览器安全模型的核心部分,旨在防止恶意网站窃取用户数据或执行未经授权的操作。
1. 什么是同源?
同源是指两个 URL 的协议(Protocol)、域名(Domain)和端口(Port)完全相同。如果其中任何一个不同,则被认为是不同源。
-
同源示例
https://example.com和https://example.com/api是同源。
-
不同源示例
https://example.com和https://api.example.com是不同源(域名不同)。http://example.com和https://example.com是不同源(协议不同)。https://example.com和https://example.com:8080是不同源(端口不同)。
2. 同源策略的作用
同源策略的主要目的是保护用户数据安全,防止恶意网站通过脚本访问其他网站的资源。具体来说,同源策略限制了以下行为:
- 访问 DOM:
- 不同源的脚本无法访问彼此的 DOM。
- 例如,
https://example.com的脚本无法访问https://another.com的 DOM。
- 发送 AJAX 请求:
- 不同源的脚本无法直接发送 AJAX 请求到其他源。
- 例如,
https://example.com的脚本无法直接请求https://api.example.com的数据。
- 读取 Cookie 或 LocalStorage:
- 不同源的脚本无法读取彼此的 Cookie 或 LocalStorage。
- 例如,
https://example.com的脚本无法读取https://another.com的 Cookie。
- 访问 iframe 内容:
- 不同源的 iframe 无法访问彼此的内容。
- 例如,
https://example.com的页面无法访问嵌入的https://another.comiframe 的内容。
3. 同源策略的例外
虽然同源策略限制了跨域访问,但有一些例外情况允许跨域交互:
- 跨域资源嵌入:
- 浏览器允许跨域嵌入某些资源,如
<img>、<script>、<link>和<iframe>。 - 例如,
https://example.com的页面可以嵌入https://another.com的图片或脚本。
- 浏览器允许跨域嵌入某些资源,如
- 跨域表单提交:
- 浏览器允许跨域提交表单(如
<form>的action属性指向不同源)。 - 例如,
https://example.com的表单可以提交到https://another.com。
- 浏览器允许跨域提交表单(如
- 跨域资源共享(CORS):
- 通过 CORS,服务器可以明确允许某些跨域请求。
- 例如,
https://example.com的脚本可以请求https://api.example.com的数据,前提是服务器配置了 CORS。
- JSONP(JSON with Padding):
- 通过动态创建
<script>标签,可以绕过同源策略获取跨域数据。 - 例如,
https://example.com的页面可以通过 JSONP 获取https://api.example.com的数据。
- 通过动态创建
- postMessage API:
- 通过
postMessageAPI,不同源的页面可以通过消息传递进行通信。 - 例如,
https://example.com的页面可以向嵌入的https://another.comiframe 发送消息。
- 通过
4. 同源策略的实际应用
4.1 防止跨站脚本攻击(XSS)
同源策略限制了脚本访问其他源的资源,从而防止恶意脚本窃取用户数据或执行未经授权的操作。
4.2 防止跨站请求伪造(CSRF)
同源策略限制了跨域请求的发送,从而防止恶意网站伪造用户请求。
4.3 保护用户隐私
同源策略限制了不同源之间的 Cookie 和 LocalStorage 访问,从而保护用户隐私。
5. 同源策略的示例
5.1 访问 DOM
-
同源:
// 假设当前页面是 https://example.com document.getElementById("element"); // 可以访问 -
不同源:
// 假设当前页面是 https://example.com const iframe = document.getElementById("iframe"); iframe.contentWindow.document.getElementById("element"); // 报错
5.2 发送 AJAX 请求
-
同源:
// 假设当前页面是 https://example.com fetch("/api/data") // 可以请求 .then((response) => response.json()) .then((data) => console.log(data)); -
不同源:
// 假设当前页面是 https://example.com fetch("https://api.example.com/data") // 报错 .then((response) => response.json()) .then((data) => console.log(data));
5.3 读取 Cookie
-
同源:
// 假设当前页面是 https://example.com document.cookie; // 可以读取 -
不同源:
// 假设当前页面是 https://example.com // 无法读取 https://another.com 的 Cookie
6. 如何绕过同源策略
虽然同源策略是浏览器的重要安全机制,但在某些情况下需要绕过它。以下是常见的绕过方法:
- CORS:
- 服务器配置
Access-Control-Allow-Origin头部字段,允许特定源的跨域请求。
- 服务器配置
- JSONP:
- 通过动态创建
<script>标签,获取跨域数据。
- 通过动态创建
- 代理服务器:
- 使用同源服务器作为代理,转发跨域请求。
- postMessage API:
- 通过消息传递实现跨域通信。
- document.domain:
- 如果两个页面属于同一主域(如
example.com和sub.example.com),可以通过设置document.domain实现跨域访问。
- 如果两个页面属于同一主域(如
7. 总结
- 同源策略是浏览器的核心安全机制,限制不同源之间的交互。
- 同源是指协议、域名和端口完全相同。
- 同源策略保护用户数据安全,防止恶意网站窃取信息或执行未经授权的操作。
- 通过 CORS、JSONP、代理服务器等方法可以绕过同源策略,实现跨域交互。