深入解析 Fetch API 的 credentials 属性:Cookie 携带机制
深入解析 Fetch API 的 credentials 属性:Cookie 携带机制
引言:为什么需要关注 credentials 属性?
在现代 Web 开发中,Fetch API 已成为发起网络请求的标准方式。其中 credentials 属性控制着请求是否携带身份凭证(如 Cookie、HTTP 认证等),这直接关系到用户认证状态和跨域资源共享(CORS)的实现。理解其工作原理对构建安全的 Web 应用至关重要。
一、credentials 的三种配置模式
1. credentials: 'omit'
行为:从不发送任何凭证
适用场景:公开 API、静态资源请求
安全级别:⭐️⭐️⭐️⭐️⭐️
fetch('https://api.example.com/data', {credentials: 'omit'
})
2. credentials: 'same-origin'
行为:仅在同源请求时发送凭证
适用场景:同源 API 调用
安全级别:⭐️⭐️⭐️⭐️
fetch('/api/user', {credentials: 'same-origin'
})
3. credentials: 'include'
行为:总是发送凭证(包括跨域请求)
适用场景:跨域认证、单点登录(SSO)
安全级别:⭐️⭐️⭐️(需额外防护)
fetch('https://auth.example.com/session', {credentials: 'include'
})
二、关键概念解析
1. 同源 vs 同站 vs 跨站
概念 | 判断标准 | 示例 |
---|---|---|
同源 | 协议+域名+端口完全相同 | https://app.com → https://app.com/api |
同站 | 相同顶级域名(eTLD+1) | https://app.com → https://api.com (共用 .com) |
跨站 | 不同顶级域名 | https://app.com → https://service.net |
2. Cookie 作用域属性
属性 | 作用 | 示例 |
---|---|---|
Domain | 指定生效域名 | Domain=.example.com (所有子域) |
Path | 指定生效路径 | Path=/api (仅 /api 路径) |
Secure | 仅通过 HTTPS 发送 | Secure |
SameSite | 控制跨站发送行为 | SameSite=None; Secure (允许跨站) |
HttpOnly | 禁止 JavaScript 访问 | HttpOnly (防 XSS) |
三、实战场景分析
基础场景设定
- 当前页面 URL:
https://app.example.com/dashboard
- 存储的 Cookie:
Cookie 名称 Domain Path Secure SameSite 作用范围 session_id .example.com / ✅ None 所有 example.com 子域 user_prefs app.example.com /dashboard ✅ Lax 仅当前路径 auth_token api.example.com / ✅ None 仅 api 子域 tracking external.com / ❌ None 仅 external.com
场景 1:同源请求
目标 URL:https://app.example.com/api/data
配置 | 发送的 Cookie | 原因分析 |
---|---|---|
omit | 无 | 明确要求不发送凭证 |
same-origin | session_id, user_prefs | 同源请求,Domain/Path 匹配 |
include | session_id, user_prefs | 同源请求,Domain/Path 匹配 |
关键点:user_prefs
因 Path 匹配 /dashboard
被发送
场景 2:同站跨域请求
目标 URL:https://api.example.com/users
配置 | 发送的 Cookie | 原因分析 |
---|---|---|
omit | 无 | 不发送任何凭证 |
same-origin | 无 | 不同源(app ≠ api) |
include | session_id, auth_token | session_id 的 Domain 包含 api,auth_token 的 Domain 精确匹配 |
关键点:user_prefs
因 Domain 不匹配(app ≠ api)未被发送
场景 3:跨站请求
目标 URL:https://external.com/data
配置 | 发送的 Cookie | 原因分析 |
---|---|---|
omit | 无 | 不发送任何凭证 |
same-origin | 无 | 不同源且不同站 |
include | tracking | Domain 精确匹配,SameSite=None |
关键点:tracking
因缺少 Secure 标记可能被浏览器阻止
四、SameSite 属性的关键影响
SameSite 三种模式对比
模式 | 同源请求 | 同站跨域请求 | 跨站请求 | 示例场景 |
---|---|---|---|---|
None | ✅ 发送 | ✅ 发送 | ✅ 发送 | 跨域认证 |
Lax | ✅ 发送 | ⚠️ 仅 GET 导航 | ❌ 不发送 | 用户会话 |
Strict | ✅ 发送 | ❌ 不发送 | ❌ 不发送 | 敏感操作 |
实际影响示例
// 假设 Cookie: sensitive=value; SameSite=Strict; Secure// 同站跨域请求
fetch('https://api.example.com/data', {credentials: 'include' // ❌ 不会发送 sensitive Cookie
})// 跨站请求
fetch('https://external.com/data', {credentials: 'include' // ❌ 不会发送 sensitive Cookie
})
Credentials 配置决策树
五、安全最佳实践
1. 最小权限原则
// 仅必要请求使用 include
if (needsAuth) {fetch(url, { credentials: 'include' })
} else {fetch(url, { credentials: 'same-origin' })
}
2. 服务器端 CORS 配置
# Nginx 配置示例
add_header 'Access-Control-Allow-Origin' 'https://app.example.com';
add_header 'Access-Control-Allow-Credentials' 'true';
add_header 'Access-Control-Allow-Methods' 'GET, POST';
3. Cookie 安全设置
# 认证 Cookie 推荐配置
Set-Cookie: session=abc123; Domain=.example.com; Path=/; Secure; HttpOnly; SameSite=None
4. CSRF 防护
// 即使使用 credentials: 'include' 也要添加 CSRF token
fetch('/api/transfer', {method: 'POST',credentials: 'include',headers: {'X-CSRF-Token': getCSRFToken()}
})
六、常见问题解决方案
问题 1:Cookie 未发送
排查步骤:
- 确认
credentials: 'include'
- 检查服务器
Access-Control-Allow-Credentials: true
- 验证 Cookie 的
SameSite=None
和Secure
- 确保协议一致(HTTP/HTTPS)
问题 2:跨域请求被阻止
错误信息:
The value of the 'Access-Control-Allow-Origin' header must not be the wildcard '*'
解决方案:
# 指定具体来源而非通配符
add_header 'Access-Control-Allow-Origin' 'https://yourdomain.com';
问题 3:IE 兼容性
解决方案:
// 使用 XHR 替代
const xhr = new XMLHttpRequest();
xhr.open('GET', url);
xhr.withCredentials = true; // 等效配置
xhr.send();
七、总结
掌握 credentials
属性的工作原理,能帮助开发者:
- 正确实现跨域认证流程
- 构建安全的身份验证系统
- 避免常见的 CORS 和 Cookie 问题
- 优化应用的安全防护体系
关键要点:
include
会发送所有 Domain/Path 匹配的 Cookiesame-origin
是大多数同源 API 的安全选择omit
提供最高安全级别但无认证能力- SameSite 和 Secure 是跨域认证的关键
通过合理配置和遵循安全最佳实践,您可以在保证用户体验的同时,构建出既强大又安全的 Web 应用。