Set-Cookie 是什么
Set-Cookie 是服务器向客户端写入状态的响应头:一条响应可以携带多个该头,每个头写一个状态项。它的属性决定了这个状态的作用范围、生存时长与安全边界——路径决定哪些请求会带上它,域决定哪些子域共享,有效期决定它是会话级还是持久化的,安全相关属性则决定它能否被脚本读取、能否在非加密连接上发送。理解这些属性是排查「登录态莫名失效」与「跨站请求伪造」的基础。
基本信息
| 名称 | Set-Cookie(RFC 6265 §4,现代属性见其修订版) |
|---|---|
| 作用 | 向客户端写入状态 |
| 可多条 | 同一响应可下发多个,用于不同状态项 |
| 同名情况 | 同名状态可按路径或域分成多份,客户端会一并发送 |
| 安全属性 | 安全传输、禁止脚本读取、限制跨站携带,缺一不可 |
推荐的完整写法
推荐的完整写法
会话标识; 路径为根; 有效期一天; 仅加密连接; 禁止脚本读取; 跨站宽松 # 会话类状态的安全组合
主题偏好; 路径为根; 有效期一年; 跨站宽松 # 非敏感偏好,可以长期保存
# 注意:一条响应里不同状态要分别写在不同的头行,不能合并属性逐项读法
| 属性 | 作用 | 写错的后果 |
|---|---|---|
| 路径 | 限定哪些请求会携带该状态 | 路径过窄导致子页面拿不到登录态 |
| 域 | 限定哪些子域共享 | 写得过宽会让子域互相覆盖状态 |
| 有效期 | 决定持久化还是会话级 | 意外变成会话级,用户关掉浏览器就要重新登录 |
| 安全传输 | 仅通过加密连接发送 | 在明文连接上也会发送,凭证可被窃听 |
| 禁止脚本读取 | 脚本无法读取该状态 | 一旦出现脚本注入,凭证被直接偷走 |
| 跨站策略 | 限制跨站请求是否携带 | 缺失时存在跨站请求伪造风险 |
观察与核对
观察与核对
curl -si https://www.example.com/ | grep -i '^set-cookie' # 看服务端下发了什么属性
curl -si https://www.example.com/me -H 'Cookie: sessionid=abc123' # 手工携带状态验证服务端行为
# 浏览器里用开发者工具的存储面板可以看到每个状态的属性与实际作用范围排障要点
- 登录后立刻掉线:先确认有效期的写法,很多实现把它误当成绝对时间
- 子域之间互相顶掉状态:检查域属性是否写成了包含所有子域的宽范围
- 某几个页面拿不到登录态:对照路径属性与实际访问路径的前缀关系
- 同一个名字出现多份:客户端会把它们全部发送,服务端解析结果取决于实现
会话类状态的安全三件套缺一不可:仅加密连接发送、禁止脚本读取、限制跨站携带。缺失时脚本注入可直接窃取凭证,或者第三方站点能诱导用户携带凭证发起请求。
只要网络是明文,任何状态写入都可能被旁观者完整看到。启用加密访问之后再给关键状态补上安全传输属性,顺序反了会先把凭证泄漏出去。
长期维护建议
- 状态项命名带业务前缀,避免与第三方组件写入的项重名,减少互相覆盖
- 多应用共享同一域名时,给各自的状态项划分清晰的作用范围
- 定期清理不再使用的状态项,历史遗留项会让每个请求的体积越来越大
- 关键状态变更后要能立即让服务端会话失效,而不只是依赖客户端丢弃本地状态