COOP、COEP、CORS 详解
目录
- 概述
- 核心概念对比
- CORS (Cross-Origin Resource Sharing)
- COEP (Cross-Origin Embedder Policy)
- COOP (Cross-Origin Opener Policy)
- 跨域隔离 (Cross-Origin Isolation)
- 其他相关概念
- 策略关系与层级
- 核心策略深度解析
- 跨域隔离与高权限 API
- 实战排查指南
- 最佳实践
- 总结
概述
在 Web 开发领域,COOP、COEP、CORS 是三种用于增强网站安全与跨域控制的 HTTP 安全策略。它们共同构建了现代 Web 应用的安全防线,帮助开发者控制跨域资源共享、资源嵌入和窗口隔离。
核心目标
- CORS:解决跨域 AJAX/API 请求的访问控制
- COEP:控制页面可以嵌入哪些跨源资源
- COOP:控制页面被跨源页面打开时的隔离级别
核心概念对比
| 特性 | CORS | COEP | COOP |
|---|---|---|---|
| 全称 | 跨源资源共享 | 跨源嵌入器策略 | 跨源开放者策略 |
| 作用对象 | 请求方 (浏览器) | 嵌入方 (页面) | 打开方 (页面) |
| 核心目的 | 控制跨域 AJAX/API 请求是否允许 | 控制页面可以嵌入哪些跨源资源 | 控制页面被跨源页面打开时的隔离级别 |
| 实现方式 | 响应头Access-Control-Allow-* | 响应头Cross-Origin-Embedder-Policy | 响应头Cross-Origin-Opener-Policy |
| 主要场景 | 脚本发起的跨域请求 | 资源加载控制 | 窗口间隔离 |
CORS (Cross-Origin Resource Sharing)
即"跨源资源共享",是开发者最熟悉的跨域方案,主要解决脚本发起的跨域 HTTP 请求(如fetch、XMLHttpRequest)。
工作原理
当浏览器发现跨域请求时,会先向目标服务器发送一个"预检请求"(OPTIONS)。服务器通过在响应头中包含Access-Control-Allow-Origin等字段,来明确告知浏览器是否允许此次跨域访问。
请求流程:
1. 浏览器发起跨域请求 2. 发送 OPTIONS 预检请求(如需要) 3. 服务器返回 CORS 响应头 4. 浏览器根据响应头决定是否允许请求关键响应头
Access-Control-Allow-Origin
指定允许访问的源:
Access-Control-Allow-Origin: * Access-Control-Allow-Origin: https://example.com说明:
*表示允许所有源,但仅适用于无凭据请求- 指定具体域名时,只能设置一个源
- 对于需要凭据的请求,必须指定具体域名,不能使用
*
Access-Control-Allow-Credentials
是否允许携带 Cookie 等凭据:
Access-Control-Allow-Credentials: true注意事项:
- 当设置为
true时,Access-Control-Allow-Origin不能为* - 必须指定具体的源
Access-Control-Allow-Methods
允许的 HTTP 方法:
Access-Control-Allow-Methods: GET, POST, PUT, DELETEAccess-Control-Allow-Headers
允许的请求头:
Access-Control-Allow-Headers: Content-Type, AuthorizationAccess-Control-Max-Age
预检请求的缓存时间(秒):
Access-Control-Max-Age: 86400简单请求 vs 预检请求
简单请求(不需要预检):
- 方法:GET、HEAD、POST
- 请求头:仅限简单请求头(如
Content-Type: text/plain) - 直接发送实际请求
预检请求(需要先发送 OPTIONS):
- 方法:PUT、DELETE、PATCH 等
- 自定义请求头
- 先发送 OPTIONS,再发送实际请求
示例配置
服务器端配置(Node.js/Express):
app.use((req,res,next)=>{res.header('Access-Control-Allow-Origin','https://example.com');res.header('Access-Control-Allow-Credentials','true');res.header('Access-Control-Allow-Methods','GET, POST, PUT, DELETE');res.header('Access-Control-Allow-Headers','Content-Type, Authorization');res.header('Access-Control-Max-Age','86400');if(req.method==='OPTIONS'){returnres.sendStatus(200);}next();});客户端请求:
// 带凭据的请求fetch('https://api.example.com/data',{credentials:'include',headers:{'Content-Type':'application/json','Authorization':'Bearer token'}}).then(response=>response.json()).then(data=>console.log(data));与 CORP 的区别
- CORS:主要解决JS 脚本的跨域读取问题
- CORP:解决的是所有资源(如
<img>、<script>)的加载许可问题
COEP (Cross-Origin Embedder Policy)
即"跨源嵌入器策略",用于限制当前页面可以加载哪些跨源资源(如图片、脚本、iframe等)。
核心指令
Cross-Origin-Embedder-Policy: require-corp作用机制
启用后,页面只能加载满足以下任一条件的跨源资源:
- 对方服务器响应头包含
Cross-Origin-Resource-Policy: cross-origin(或same-site/same-origin) - 通过 CORS 机制明确授权(如带凭据的请求)
目的
确保页面加载的每一个跨源资源都得到了资源所有者的明确许可,是构建"跨域隔离"环境的关键一环。
递归生效
此策略会递归应用于页面内的所有 iframe 和资源,要求整个嵌入树都符合规范。
调试技巧
可先使用Cross-Origin-Embedder-Policy-Report-Only头进行灰度测试,只报告违规资源而不阻止加载,便于排查问题:
Cross-Origin-Embedder-Policy-Report-Only: require-corp示例配置
服务器端配置:
Cross-Origin-Embedder-Policy: require-corp资源服务器配置(CDN):
Cross-Origin-Resource-Policy: cross-originHTML 中使用:
<!-- 需要添加 crossorigin 属性 --><scriptsrc="https://cdn.example.com/lib.js"crossorigin></script><imgsrc="https://cdn.example.com/image.jpg"crossorigin>COOP (Cross-Origin Opener Policy)
即"跨源开放者策略",主要管理通过window.open()或链接打开的新窗口/标签页之间的隔离关系。
核心指令
Cross-Origin-Opener-Policy: same-origin作用机制
启用后,若当前页面(A)打开了一个不同源的页面(B):
- 在页面 A 中,
window.open()返回的 B 窗口对象其closed属性为true,且无法通过B.opener访问到 A 的window对象(值为null) - 两个页面将被放入不同的"浏览上下文组",在进程和内存上实现隔离
可选值
| 值 | 说明 |
|---|---|
unsafe-none | 默认值,允许共享上下文,可通过window.opener互相访问 |
same-origin-allow-popups | 与同源或同样设置了此值的页面打开的弹窗共享上下文 |
same-origin | 与任何跨源页面打开的弹窗都断开上下文,实现完全隔离 |
目的
防止恶意网站通过新窗口访问或导航你的页面,从而窃取数据,是"跨域隔离"的另一关键支柱。
与 rel=“noopener” 的区别
rel="noopener":仅对当前页面发起的链接有效- COOP:从被打开的页面角度,主动声明是否断开与原页面的连接,防护能力更强
示例:
<!-- 使用 rel="noopener" --><ahref="https://example.com"target="_blank"rel="noopener">链接</a><!-- 使用 COOP(在目标页面设置) --><!-- 在 example.com 的响应头中设置 -->Cross-Origin-Opener-Policy: same-origin跨域隔离 (Cross-Origin Isolation)
通过组合COEP和COOP两个策略,可以创建一个"跨域隔离环境"。在此环境下,页面可以重新启用一些因安全原因(如 Spectre 漏洞)而被禁用的强大功能。
启用条件
同时满足以下两个条件:
Cross-Origin-Opener-Policy: same-origin Cross-Origin-Embedder-Policy: require-corp检测方法
在页面中检查self.crossOriginIsolated属性是否为true:
if(self.crossOriginIsolated){console.log('页面处于跨域隔离状态');// 可以使用 SharedArrayBuffer 等 API}else{console.log('页面未处于跨域隔离状态');}解锁的能力
进入跨域隔离状态后,以下 API 将恢复高精度或可用:
SharedArrayBuffer:用于高性能多线程和 WASMperformance.now()/performance.timeOrigin:精度恢复至 5μs 级别performance.measureUserAgentSpecificMemory():内存测量 API- JS Self-Profiling API:性能分析 API
- 部分 WASM 多线程能力:WebAssembly 多线程支持
注意事项
- 禁止修改
document.domain:在跨域隔离环境下,此操作会抛出异常,影响一些老项目 - 浏览器兼容性:目前主流浏览器(Chrome/Edge/Firefox)均已支持,但 Safari 的支持进度可能稍慢,上线前需充分测试
其他相关概念
同源策略 (Same-Origin Policy)
所有跨域策略的基石。它默认禁止一个源的文档访问另一个源的敏感资源(如 DOM、本地存储等)。CORS、COEP、COOP 等策略都是在同源策略基础上,为特定场景提供"受控的例外"。
同源判断标准:
- 协议相同(http/https)
- 域名相同
- 端口相同
CORP (Cross-Origin-Resource-Policy)
即"跨源资源策略",由资源服务器设置,声明该资源允许被哪些来源加载。它是实现 COEPrequire-corp要求的关键。
可选值:
| 值 | 说明 |
|---|---|
same-origin | 仅同源可加载 |
same-site | 仅同站点(eTLD+1)可加载 |
cross-origin | 任何源均可加载(CDN 资源常用) |
示例配置:
Cross-Origin-Resource-Policy: cross-originCORB (Cross-Origin Read Blocking)
即"跨源读取阻止"。浏览器在底层自动阻止对某些敏感类型响应(如 HTML、JSON)的读取,即使它们已被加载到内存中,以防止通过侧信道攻击(如 Spectre)窃取数据。
rel=“noopener”
一个 HTML 链接属性,作用类似于 COOP,但仅对当前页面有效。它能切断新开页面通过window.opener访问原页面的能力,常用于防止target="_blank"链接带来的安全风险。
示例:
<ahref="https://example.com"target="_blank"rel="noopener noreferrer">链接</a>策略关系与层级
这些安全策略并非孤立存在,而是层层递进,共同构建安全防线:
┌─────────────────────────────────────┐ │ 安全策略层级关系 │ ├─────────────────────────────────────┤ │ 1. 同源策略 (Same-Origin Policy) │ │ ↓ │ │ 2. CORS (跨源资源共享) │ │ ↓ │ │ 3. CORP (跨源资源策略) │ │ ↓ │ │ 4. COEP (跨源嵌入器策略) │ │ ↓ │ │ 5. COOP (跨源开放者策略) │ │ ↓ │ │ 6. 跨域隔离 (Cross-Origin Isolation)│ └─────────────────────────────────────┘关系说明:
- 同源策略:所有策略的基石,默认禁止跨源访问
- CORS:在同源策略基础上,为"脚本请求"开了一个可控的口子
- CORP:资源服务器声明"我这个资源允许谁加载",是更底层的资源级许可
- COEP:页面声明"我只加载被明确许可的资源",强制要求所有跨源资源必须通过 CORP 或 CORS 授权
- COOP:页面声明"我不与跨源页面共享执行上下文",用于隔离窗口,防御 XS-Leaks 等攻击
- 跨域隔离:当
COEP: require-corp与COOP: same-origin同时满足时,页面进入此状态,从而解锁SharedArrayBuffer等高权限 API
核心策略深度解析
1. CORS:解决"脚本请求"的跨域
触发条件
通过fetch/XMLHttpRequest发起的跨源请求,且不满足"简单请求"条件时,会先发OPTIONS预检请求。
关键响应头
Access-Control-Allow-Origin: 指定允许访问的源,*仅适用于无凭据请求Access-Control-Allow-Credentials: 是否允许携带 Cookie 等凭据Access-Control-Allow-Methods/Access-Control-Allow-Headers: 允许的 HTTP 方法和请求头
与 CORP 的区别
- CORS:主要解决JS 脚本的跨域读取问题
- CORP:解决的是所有资源(如
<img>、<script>)的加载许可问题
2. CORP:资源服务器的"加载许可"
作用
由资源服务器设置,声明该资源允许被哪些来源加载,是 COEPrequire-corp生效的前提。
可选值
same-origin: 仅同源可加载same-site: 仅同站点(eTLD+1)可加载cross-origin: 任何源均可加载(CDN 资源常用)
实战要点
- 若未设置 CORP,浏览器会将其视为
same-origin。在开启 COEP 的环境下,这会导致跨域资源加载失败 - 对于 CDN 资源,通常需要显式设置
Cross-Origin-Resource-Policy: cross-origin,并在<script>或<img>标签上添加crossorigin属性
3. COEP:页面的"资源白名单"
作用
页面通过设置Cross-Origin-Embedder-Policy: require-corp,强制要求所有跨源资源必须通过 CORP 或 CORS 授权,否则将被浏览器阻止加载。
递归生效
此策略会递归应用于页面内的所有 iframe 和资源,要求整个嵌入树都符合规范。
调试技巧
可先使用Cross-Origin-Embedder-Policy-Report-Only头进行灰度测试,只报告违规资源而不阻止加载,便于排查问题。
4. COOP:窗口间的"上下文隔离"
作用
通过设置Cross-Origin-Opener-Policy,控制顶级页面与新打开窗口之间的window.opener引用关系,实现进程隔离,防御 Spectre 等侧信道攻击。
可选值
unsafe-none(默认): 允许共享上下文,可通过window.opener互相访问same-origin-allow-popups: 与同源或同样设置了此值的页面打开的弹窗共享上下文same-origin: 与任何跨源页面打开的弹窗都断开上下文,实现完全隔离
与 rel=“noopener” 的区别
rel="noopener"仅对当前页面发起的链接有效;而 COOP 是从被打开的页面角度,主动声明是否断开与原页面的连接,防护能力更强。
跨域隔离与高权限 API
1. 为何需要跨域隔离
Spectre 等 CPU 漏洞使得攻击者能通过高精度计时器(如performance.now())和共享内存(SharedArrayBuffer)从进程内存中窃取数据。为应对此威胁,浏览器默认禁用了这些强大但危险的功能。
2. 如何进入跨域隔离状态
同时满足以下两个条件即可:
Cross-Origin-Opener-Policy: same-origin Cross-Origin-Embedder-Policy: require-corp检测方法:在页面中检查self.crossOriginIsolated属性是否为true。
3. 解锁的能力
进入跨域隔离状态后,以下 API 将恢复高精度或可用:
SharedArrayBuffer:用于高性能多线程和 WASMperformance.now()/performance.timeOrigin:精度恢复至 5μs 级别performance.measureUserAgentSpecificMemory():内存测量 API- JS Self-Profiling API:性能分析 API
- 部分 WASM 多线程能力
4. 注意事项
- 禁止修改
document.domain:在跨域隔离环境下,此操作会抛出异常,影响一些老项目 - 浏览器兼容性:目前主流浏览器(Chrome/Edge/Firefox)均已支持,但 Safari 的支持进度可能稍慢,上线前需充分测试
实战排查指南
1. CDN 资源加载失败
现象:控制台报错"Failed to load resource: COEP: cross-origin resources must be CORS-enabled or use CORP"。
原因:开启 COEP 后,浏览器要求所有跨源资源必须通过 CORS 或 CORP 授权。
解决方案:
- 在 CDN 服务器响应头中添加
Cross-Origin-Resource-Policy: cross-origin - 在页面引入资源时,添加
crossorigin属性:<scriptsrc="https://cdn.example.com/lib.js"crossorigin></script><imgsrc="https://cdn.example.com/image.jpg"crossorigin>
2. SharedArrayBuffer is not defined
原因:页面未进入跨域隔离状态。
排查步骤:
- 检查响应头是否正确设置了
COEP: require-corp和COOP: same-origin - 确认所有跨源资源(尤其是 CDN 资源)都已正确配置 CORP 或 CORS
- 在页面中打印
self.crossOriginIsolated,检查其值是否为true
3. 弹窗间 window.opener 为 null
原因:对方页面设置了COOP: same-origin或same-origin-allow-popups,主动切断了上下文关联。
解决方案:如果确实需要与原页面通信,可以协商对方将 COOP 改为unsafe-none,或改用postMessage进行通信。
4. 使用 Report-Only 模式调试
在正式启用策略前,可以使用Report-Only模式进行测试:
Cross-Origin-Embedder-Policy-Report-Only: require-corp Cross-Origin-Opener-Policy-Report-Only: same-origin这样只会报告违规资源,而不会阻止加载,便于排查问题。
最佳实践
1. 渐进式启用
- 先使用
Report-Only模式测试 - 逐步修复违规资源
- 确认无误后正式启用
2. CDN 资源配置
对于 CDN 资源,建议:
- 设置
Cross-Origin-Resource-Policy: cross-origin - 在 HTML 中添加
crossorigin属性 - 确保 CORS 配置正确(如需要)
3. 跨域隔离启用
如果需要使用SharedArrayBuffer等 API:
- 确保所有跨源资源都配置了 CORP 或 CORS
- 同时设置 COEP 和 COOP
- 使用
self.crossOriginIsolated检测状态 - 充分测试浏览器兼容性
4. 错误处理
// 检测跨域隔离状态if(!self.crossOriginIsolated){console.warn('页面未处于跨域隔离状态,某些 API 可能不可用');// 降级处理}// 检测 SharedArrayBuffer 可用性if(typeofSharedArrayBuffer==='undefined'){console.warn('SharedArrayBuffer 不可用');// 使用替代方案}总结
核心要点
- CORS:解决脚本跨域请求的访问控制
- COEP:控制页面可以嵌入哪些跨源资源
- COOP:控制页面被跨源页面打开时的隔离级别
- 跨域隔离:组合 COEP 和 COOP,解锁高权限 API
使用场景
- CORS:API 跨域请求、资源共享
- COEP:需要严格控制资源加载的场景
- COOP:需要窗口隔离的场景
- 跨域隔离:需要使用
SharedArrayBuffer等高性能 API
注意事项
- 启用策略前充分测试
- 确保所有跨源资源都正确配置
- 注意浏览器兼容性
- 使用
Report-Only模式进行灰度测试
相关资源
- MDN - CORS
- MDN - COEP
- MDN - COOP
- Web.dev - Cross-Origin Isolation