Cross-Origin 策略
跨源(Cross-Origin)策略是浏览器安全模型的核心组成部分,它控制不同源(协议、域名、端口)之间的资源访问和交互。本节将介绍 CORS(跨源资源共享)基础、HTML 中的 crossorigin 属性、以及 COOP(Cross-Origin-Opener-Policy)、COEP(Cross-Origin-Embedder-Policy)和 CORB(Cross-Origin Read Blocking)等高级安全策略。
前置知识
阅读本节前,建议先了解:Permissions Policy
同源策略
浏览器的同源策略(Same-Origin Policy, SOP)限制不同源之间的资源访问:
| 源 | 协议 | 域名 | 端口 |
|---|---|---|---|
| A | https:// | example.com | 443 |
| B | https:// | example.com | 443 |
| C | http:// | example.com | 443 |
| D | https:// | www.example.com | 443 |
| E | https:// | example.com | 8080 |
CORS 基础
简单请求
服务器通过 Access-Control-Allow-Origin 响应头授权跨域请求:
# 服务器响应头
Access-Control-Allow-Origin: https://trusted.example.com
Access-Control-Allow-Methods: GET, POST, PUT, DELETE
Access-Control-Allow-Headers: Content-Type, Authorization
Access-Control-Allow-Credentials: true
Access-Control-Max-Age: 3600预检请求(Preflight)
对于非简单请求(如自定义头、PUT/DELETE 方法),浏览器会先发送 OPTIONS 预检请求:
# 预检请求
OPTIONS /api/data HTTP/1.1
Origin: https://example.com
Access-Control-Request-Method: PUT
Access-Control-Request-Headers: Content-Type, X-Custom-Header
# 预检响应
HTTP/1.1 200 OK
Access-Control-Allow-Origin: https://example.com
Access-Control-Allow-Methods: GET, PUT, POST, DELETE
Access-Control-Allow-Headers: Content-Type, X-Custom-Header
Access-Control-Max-Age: 3600HTML crossorigin 属性
script 标签
html
<!-- 不带 crossorigin:不发送凭据 -->
<script src="https://cdn.example.com/lib.js"></script>
<!-- 错误:如果服务器需要 CORS 凭据,会报错 -->
<!-- 带 crossorigin="anonymous":发送不带凭据的跨域请求 -->
<script
src="https://cdn.example.com/lib.js"
crossorigin="anonymous"
integrity="sha384-abc123..."
></script>
<!-- 带 crossorigin="use-credentials":发送带凭据的跨域请求 -->
<script
src="https://api.example.com/auth.js"
crossorigin="use-credentials"
></script>img 标签
html
<!-- 图片默认不发送跨域凭据 -->
<img src="https://cdn.example.com/photo.jpg" alt="照片" />
<!-- 带 crossorigin:可以读取跨域图片的像素数据 -->
<img src="https://cdn.example.com/photo.jpg" crossorigin="anonymous" alt="照片" />
<!-- 使用场景:Canvas 读取跨域图片 -->
<canvas id="canvas"></canvas>
<script>
const img = new Image();
img.crossOrigin = 'anonymous'; // 必须设置才能读取像素
img.src = 'https://cdn.example.com/photo.jpg';
img.onload = function() {
const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');
ctx.drawImage(img, 0, 0);
// 可以读取像素数据
const data = ctx.getImageData(0, 0, canvas.width, canvas.height);
};
</script>link 标签
html
<!-- 字体文件需要 crossorigin 才能正确加载 -->
<link
rel="preload"
href="https://fonts.gstatic.com/s/notosanssc.woff2"
as="font"
type="font/woff2"
crossorigin="anonymous"
>audio/video 标签
html
<!-- 跨域媒体资源 -->
<video
src="https://video.example.com/stream.m3u8"
crossorigin="anonymous"
controls
></video>
<audio
src="https://audio.example.com/podcast.mp3"
crossorigin="anonymous"
controls
></audio>COOP / COEP / CORB
Cross-Origin-Opener-Policy (COOP)
防止跨域窗口(通过 window.open 或 target="_blank")之间的交互:
# 服务器响应头
Cross-Origin-Opener-Policy: same-originhtml
<!-- 启用 COOP 后,跨域打开的窗口无法访问 opener -->
<a href="https://other-site.com" target="_blank" rel="noopener">
安全打开新窗口
</a>| COOP 值 | 说明 |
|---|---|
same-origin | 仅允许同源窗口访问(推荐) |
same-origin-allow-popups | 允许通过 target=_blank 打开的窗口访问 |
unsafe-none | 不限制(默认) |
Cross-Origin-Embedder-Policy (COEP)
控制页面可以加载哪些跨域资源:
# 服务器响应头
Cross-Origin-Embedder-Policy: require-corp| COEP 值 | 说明 |
|---|---|
require-corp | 所有跨域资源需要 CORS 头 |
credentialless | 允许无凭据的跨域请求 |
Cross-Origin-Resource-Policy (CORP)
控制哪些源可以加载当前页面的资源:
# 服务器响应头
Cross-Origin-Resource-Policy: same-origin| CORP 值 | 说明 |
|---|---|
same-origin | 仅同源可以加载 |
same-site | 仅同站点可以加载 |
cross-origin | 所有跨域请求(默认) |
CORB (Cross-Origin Read Blocking)
CORB 是浏览器自动保护机制,防止跨域资源被错误地作为敏感类型(HTML/XML/JSON)读取。
完整安全策略示例
# 综合安全响应头
Content-Security-Policy: default-src 'self'; script-src 'self' https://cdn.example.com; frame-ancestors 'none';
Permissions-Policy: camera=(), microphone=(), geolocation=(self), fullscreen=*
Cross-Origin-Opener-Policy: same-origin
Cross-Origin-Embedder-Policy: require-corp
Cross-Origin-Resource-Policy: same-origin
X-Content-Type-Options: nosniff
X-Frame-Options: DENY
Referrer-Policy: strict-origin-when-cross-origin
Strict-Transport-Security: max-age=31536000; includeSubDomains注意事项
- SRI 需要 crossorigin:使用 integrity 属性时必须设置 crossorigin
- Canvas 读取跨域图片需要 crossorigin:否则会报 tainted canvas 错误
- COOP/COEP 会影响第三方内容:启用前测试页面功能
- CORS 配置在服务器端:HTML 中的 crossorigin 只是客户端设置
- **不要使用 Access-Control-Allow-Origin: ***:有安全风险
最佳实践
- CDN 资源使用 crossorigin="anonymous"
- SRI 配合 crossorigin 使用
- 启用 COOP 防止窗口间攻击
- 根据需要启用 COEP 和 CORP
- 使用
rel="noopener"保护target="_blank"链接 - 服务器端正确配置 CORS
- 使用综合安全策略保护网站
本教程已完成
恭喜你完成了 HTML5 教程的全部学习!建议回顾各章节的核心知识点,结合实战项目巩固所学内容。