同源策略的例外情况
字数 2413 2025-11-28 11:27:12
同源策略的例外情况
同源策略是浏览器的一项核心安全机制,它阻止一个源的文档或脚本与另一个源的资源进行交互。然而,为了实现特定的功能,也存在一些精心设计的例外。这些例外允许受控的跨源交互。
1. 跨域资源嵌入
某些类型的资源可以被嵌入到页面中,即使它们来自不同的源。浏览器会加载这些资源,但通常限制页面中的脚本访问其内容。
- 如何运作:当浏览器解析到指向外部源的特定HTML标签时,它会发起一个GET请求来加载该资源。
- 例子:
<script src="..."></script>:用于加载跨域的JavaScript库(如CDN上的jQuery)。<link rel="stylesheet" href="...">:用于加载跨域的CSS文件。<img>、<video>、<audio>:用于显示跨域的图片和媒体。<iframe>:可以嵌入整个跨域页面。
- 访问限制:对于
<script>和<link>,浏览器会加载并执行/应用它们,但你的页面脚本通常无法直接读取这些外部资源的内容。对于<iframe>,你无法通过contentDocument访问其内部文档对象,除非满足特定条件(如下文所述)。
2. CORS(跨源资源共享)
CORS是一种W3C标准,它允许服务器明确地告诉浏览器,哪些外部源被允许访问其资源。这是现代Web应用中实现安全跨域请求的最主要方式。
- 如何运作:当一个前端脚本(使用JavaScript的
fetch或XMLHttpRequest)试图发起一个跨域请求时,浏览器会自动在请求头中添加一个Origin字段,表明请求来自哪个源。服务器根据其策略,在响应头中返回相应的CORS头信息。 - 关键响应头:
Access-Control-Allow-Origin:这是最重要的头。它的值可以是允许访问的特定源(如https://example.com),或者对于公共API,可以是通配符*。Access-Control-Allow-Methods:指定允许的HTTP方法(如GET, POST, PUT)。Access-Control-Allow-Headers:指定允许的自定义请求头。
- 预检请求:对于可能对服务器数据产生副作用的“非简单请求”(如使用
PUT方法或带有自定义头的POST请求),浏览器会首先自动发送一个OPTIONS方法的“预检请求”,以确认实际请求是否安全。只有预检请求通过后,才会发送真正的请求。
3. 文档片段标识符(Fragment Identifier)和URL片段
这种方法利用了URL中 # 后面的部分(称为片段标识符)改变时,页面不会刷新的特性。
- 如何运作:一个页面可以通过修改另一个跨域
<iframe>或窗口的URL哈希值(即#后面的部分)来传递数据。接收方页面需要通过监听window.onhashchange事件来捕获这个变化并读取数据。 - 限制:这种方法只能传递少量数据,并且是单向的(父页面向子iframe传递)。它不安全,因为数据暴露在URL中。这是一种较老的技术,在现代应用中已被
postMessage取代。
4. window.postMessage
postMessage 提供了一个安全、可控的跨文档通信机制。
- 如何运作:它允许来自不同源的窗口(如一个页面和它嵌入的
<iframe>,或通过window.open打开的弹出窗口)之间相互发送消息。 - 语法:
otherWindow.postMessage(message, targetOrigin);otherWindow:是对另一个窗口的引用(如iframe.contentWindow)。message:要发送的数据。targetOrigin:一个安全限制。指定哪些源可以接收此消息。可以是具体的源(如"https://target-site.com")或通配符"*"(不推荐,因为不安全)。
- 接收消息:目标窗口需要通过监听
message事件来接收消息,并可以从事件对象中验证发送方的源(event.origin)以确保安全。
5. JSONP(JSON with Padding)
JSONP是一种利用 <script> 标签可以跨域的特性来实现跨域数据请求的古老方法。
- 如何运作:它不使用
XMLHttpRequest,而是动态创建一个<script>标签,其src指向一个API端点,并在URL中附带一个回调函数名(如?callback=handleResponse)。服务器不是返回纯JSON,而是返回一段调用该回调函数的JavaScript代码,并将JSON数据作为参数传入。 - 例子:
- 你的代码:
<script src="https://api.example.com/data?callback=myCallback"></script> - 服务器响应:
myCallback({"name": "Alice", "age": 30}); - 你的代码中需要提前定义
myCallback函数来处理数据。
- 你的代码:
- 缺点:只支持GET请求,错误处理困难,并且存在严重的安全风险,因为它信任并执行服务器返回的任意JavaScript代码。在现代开发中,应优先使用CORS,JSONP已被视为过时且不安全的技术。
总结
这些例外并非安全漏洞,而是为了平衡安全性与功能性而设计的机制。它们各自有明确的适用场景和安全边界。开发者在实现跨域功能时,应优先选择CORS和 postMessage 这些现代、安全且功能强大的方法。