基本介绍
同源策略(Same-Origin Policy, SOP)是一种约定,是浏览器最重要的安全策略之一。它用于限制一个源(origin)的文档或脚本如何与另一个源的资源进行交互。这是一个用于隔离潜在恶意文件的关键安全机制。
定义源(Origin)
在同源策略中,“源”由三部分组成:
- 协议(Protocol):例如,HTTP、HTTPS。
-
域名(Host):例如,
www.example.***
。 - 端口(Port):例如,80(HTTP的默认端口)、443(HTTPS的默认端口)。
只有当这三部分完全匹配时,两个 URL 才属于同一个源。
同源策略的限制
同源策略主要限制了以下几种情况下的资源交互:
- DOM:一个源中加载的脚本不能访问另一个源加载的文档的 DOM。
- AJAX 请求:XMLHttpRequest 和 Fetch API 遵循同源策略,这意味着使用这些技术的 Web 应用程序只能向同一个源发起 HTTP 请求,而不能直接向不同源的服务器发起请求。
- Cookies、LocalStorage 和 IndexDB:Web 应用程序只能访问同源的数据。
绕过同源策略
虽然同源策略对提高 Web 安全性至关重要,但在实际开发中,经常需要与不同源的服务器交互。为了安全地实现这种交互,引入了一些机制:
- CORS(跨源资源共享):允许服务器通过在响应头中添加特定的头信息,来告知浏览器允许哪些源访问该资源。
-
JSONP(JSON with Padding):通过动态创建
<script>
标签的方式来绕过同源策略,但只能用于 GET 请求。 - WebSockets:虽然 WebSocket 协议不受同源策略限制,但在新的 WebSocket 连接建立过程中,服务器可以根据来源判断是否接受连接。
-
Document.domain:通过设置
document.domain
属性来放宽同源策略的限制,但这只适用于具有相同父域的不同子域之间的交互。 - PostMessage API:允许不同源之间的安全通信。
同源策略是 Web 安全的基石,理解它的工作原理和如何在必要时安全地绕过它,对于开发安全的 Web 应用至关重要。
示例
下面,我们通过一些具体的例子来说明同源策略(Same-Origin Policy)的影响以及如何安全地绕过这些限制。
示例 1:同源策略限制
假设有两个页面,一个来自 http://www.example.***
,另一个来自 http://www.another.***
。
-
页面 A (
http://www.example.***/pageA.html
) -
页面 B (
http://www.another.***/pageB.html
)
如果页面 A 中的 JavaScript 试图访问页面 B 的 DOM,比如尝试读取一个 iframe 内容,这将会失败,因为两个页面不满足同源策略(协议、域名和端口必须全部匹配)。
示例 2:CORS 绕过同源策略
现在,假设 http://www.example.***
的前端页面需要向 http://api.another.***
发送 AJAX 请求。
默认情况下,这种跨源请求会被浏览器的同源策略阻止。但是,如果 http://api.another.***
的服务器配置了 CORS(跨源资源共享)策略,比如通过添加以下响应头:
A***ess-Control-Allow-Origin: http://www.example.***
那么来自 http://www.example.***
的前端页面就能成功地向 http://api.another.***
发送 AJAX 请求并接收响应。
示例 3:使用 JSONP 绕过同源策略
考虑一个需要从 http://www.example.***
向 http://api.another.***
发送数据请求的场景,但后端服务不支持 CORS。在这种情况下,可以使用 JSONP。
http://www.example.***
的前端页面可以动态创建一个 <script>
标签,其 src
属性指向 http://api.another.***
的一个服务,并且该服务能返回一个 JSONP 响应。
<script src="http://api.another.***/data?callback=handleResponse"></script>
然后,http://api.another.***
返回一个响应,形如:
handleResponse({ "key": "value" });
这里的 handleResponse
是在 http://www.example.***
页面上定义的一个函数,用于处理从 http://api.another.***
返回的数据。
示例 4:使用 PostMessage 进行通信
如果 http://www.example.***/pageA.html
内嵌了一个来自 http://www.another.***/pageB.html
的 iframe,并且这两个页面需要相互通信,可以使用 window.postMessage()
方法。
在 pageA.html
中:
var iframe = document.getElementById('myIframe');
iframe.contentWindow.postMessage('Hello from A!', 'http://www.another.***');
在 pageB.html
中:
window.addEventListener('message', function(event) {
if (event.origin === 'http://www.example.***') {
console.log('Message from A:', event.data);
}
});
这种方式允许两个不同源的页面安全地通信,而不违反同源策略。
这些示例展示了同源策略如何影响 Web 应用的交互,以及开发者可以如何利用 CORS、JSONP 和 postMessage
等技术在保证安全的前提下绕过这些限制。