前端请求中的 credentials、Cookie 和跨域凭证如何理解?
简化版
credentials 控制 Fetch 请求是否携带 Cookie、HTTP 认证信息和 TLS 客户端证书等凭证。跨域请求要带 Cookie,前端需设置 credentials: 'include',服务端还必须返回精确 Access-Control-Allow-Origin 和 Access-Control-Allow-Credentials: true,不能用 *。
详细版
Fetch 的常见取值包括 omit、same-origin、include。同源请求通常默认携带凭证;跨源请求如果要携带 Cookie,必须显式 include。
fetch('https://api.example.com/me', {
credentials: 'include',
})
服务端响应要类似:
Access-Control-Allow-Origin: https://www.example.com
Access-Control-Allow-Credentials: true
同时 Cookie 自身还受 SameSite、Secure、Domain、Path 等属性影响。面试要把“前端请求配置”“服务端 CORS 响应”“Cookie 属性”三件事放在一起说。
完整版教学
一、credentials 控制的是什么
浏览器请求不是只有 URL 和 body,还可能自动携带身份信息。Cookie 是最常见的凭证,另外还包括 HTTP Basic 认证信息、客户端证书等。credentials 控制的是这些凭证是否随请求发送,以及响应中的 Set-Cookie 是否被接受。
| 配置 | 同源请求 | 跨源请求 | 典型用途 |
|---|---|---|---|
omit | 不带 | 不带 | 纯公开资源 |
same-origin | 带 | 不带 | 默认安全策略 |
include | 带 | 带 | 跨域登录态 API |
记忆钩子:跨域 Cookie 成功要三把钥匙:前端
include、服务端 credentials、Cookie 自身允许跨站。
二、为什么跨源不能默认带 Cookie
如果浏览器跨站请求默认携带 Cookie,任意恶意站点都能更容易借用户登录态访问其他站点接口。浏览器把跨源凭证设成显式选择,是为了减少 CSRF 和隐私泄露风险。
evil.com
-> fetch('https://bank.com/api/me')
-> 若默认带 Cookie,会扩大跨站探测和攻击面
即使设置了 include,浏览器仍会执行 CORS 检查。前端代码无法单方面突破浏览器安全策略。
三、服务端 CORS 必须配合
Access-Control-Allow-Origin: https://app.example.com
Access-Control-Allow-Credentials: true
Vary: Origin
携带凭证时,Access-Control-Allow-Origin 不能是 *,必须是精确源。原因很直接:带凭证的响应可能包含用户私有数据,不能被任意站点读取。
Vary: Origin 也很重要。若 CDN 缓存了一个带 Access-Control-Allow-Origin 的响应,却没有按 Origin 区分缓存,可能把 A 站允许的响应头错误复用给 B 站。
四、Cookie 属性也会拦截
Set-Cookie: sid=abc; SameSite=None; Secure; HttpOnly
跨站 iframe 或跨站 XHR 要携带 Cookie 时,现代浏览器通常要求 SameSite=None; Secure。如果 Cookie 是 SameSite=Lax 或 Strict,即使 Fetch 设置 credentials: 'include',某些跨站场景也不会带上它。
因此排查跨域 Cookie 失败时不能只看 JavaScript。要同时看请求是否带 Cookie、响应 CORS 是否允许、Cookie 是否被浏览器保存、SameSite 是否满足场景。
五、预检请求不等于真实请求
复杂跨域请求会先发 OPTIONS 预检。预检用于询问服务端是否允许方法、头部和凭证策略;预检成功后,浏览器才会发真实请求。
OPTIONS /api/update
-> Access-Control-Allow-Methods: POST
-> Access-Control-Allow-Headers: Content-Type
POST /api/update
-> 携带 Cookie
如果预检失败,真实请求根本不会发送。很多同学在 Network 里只看到 OPTIONS,就以为接口没调用,其实是浏览器在安全检查阶段拦住了。
六、安全取舍
跨域带凭证是强能力,意味着另一个前端源可以代表用户读取私有接口响应。服务端必须严格维护白名单,不要为了省事反射任意 Origin。
| 做法 | 风险 |
|---|---|
| 允许任意 Origin 携带凭证 | 高风险 |
精确白名单 + Vary: Origin | 推荐 |
Cookie 配 SameSite=None 但无 CSRF 防护 | 有风险 |
| 所有 API 都允许跨域 | 攻击面变大 |
跨域凭证配置经常和 CSRF、SameSite、CORS 安全一起考,答题时要主动提醒“能跨域访问”不等于“应该广泛开放”。
七、常见误区与追问
- 误区:前端设置
credentials: include就一定能带 Cookie。 Cookie 属性和服务端 CORS 都必须配合。 - 误区:
Access-Control-Allow-Origin: *可以和凭证一起用。 带凭证响应必须使用精确 Origin。 - 误区:OPTIONS 请求失败不影响 POST。 预检失败时真实请求不会发出。
- 追问:为什么要加
Vary: Origin? 避免缓存层把一个 Origin 的 CORS 响应复用给另一个 Origin。 - 追问:XHR 怎么设置跨域凭证? 使用
xhr.withCredentials = true。 - 追问:为什么 Cookie 保存了但请求没带? 可能是 SameSite、Domain、Path、Secure 或请求源不满足。
八、加强记忆
跨域凭证题可以按“三方会审”记:前端请求要声明 include,服务端 CORS 要精确允许,Cookie 属性要允许当前站点关系。任何一方不通过,浏览器都不会让请求按你想象的方式带上登录态。安全上也要记住,跨域带凭证意味着访问用户私有数据,白名单和 CSRF 防护不能省。