同源策略的例外情况
字数 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的 fetchXMLHttpRequest)试图发起一个跨域请求时,浏览器会自动在请求头中添加一个 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 这些现代、安全且功能强大的方法。

同源策略的例外情况 同源策略是浏览器的一项核心安全机制,它阻止一个源的文档或脚本与另一个源的资源进行交互。然而,为了实现特定的功能,也存在一些精心设计的例外。这些例外允许受控的跨源交互。 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 这些现代、安全且功能强大的方法。