Web之深入解析Cookie的安全防御与跨域实践

一、什么是 Cookie?

  • 简单说:Cookie 是网站为了记住你,存放在你浏览器里的一小段文本信息,就像一张"临时身份证"或"便签条"。
  • 工作原理:
    • 访问网站时,服务器可以生成一个 Cookie 并发送给你的浏览器;
    • 浏览器会把它保存下来;
    • 下次再访问同一个网站时,浏览器会自动把这个 Cookie 带上,发给服务器;
    • 服务器通过读取 Cookie 就知道"哦,又是你",从而提供个性化内容(比如保持登录状态)。
  • 特点:
    • 大小有限,一般每个 Cookie 不超过 4KB;
    • 有有效期,可以是"会话级"(关闭浏览器就消失),也可以是"持久化"(比如 7 天后过期);
    • 遵循同源策略(但有一些放宽机制,后面会讲到)。

二、Cookie 的结构与属性

  • 一个 Cookie 由"键值对"和若干"元数据属性"组成,如下所示,HTTP 响应头中的 Set-Cookie:
swift 复制代码
Set-Cookie: sessionId=abc123; Domain=.example.com; Path=/shop; Expires=Wed, 21 Oct 2026 07:28:00 GMT; Secure; HttpOnly; SameSite=Lax
  • 必选部分:Name=Value:例如 sessionId=abc123,存储实际数据。
  • 可选属性(控制行为):
属性 含义 结构
Domain 指定哪些主机可以接收该 Cookie。默认为当前域名(不含子域) Domain=.example.com 允许所有 *.example.com 子域共享此 Cookie
Path 指定 URL 路径下才发送 Cookie Path=/shop 表示仅当请求 /shop 或其子路径时携带
Expires / Max-Age 控制有效期,Expires 指定绝对过期时间;Max-Age 指定相对秒数(现代优先),不设置则为会话级 Cookie(关闭浏览器即删除) Max-Age=3600 表示 1 小时后失效
Secure 标记后,Cookie 仅能通过 HTTPS 协议传输 防止中间人攻击窃取
HttpOnly 标记后,无法通过 document.cookie 访问,只能由 HTTP 请求携带 防范 XSS 攻击盗取 Cookie
SameSite 控制跨站请求是否发送 Cookie 值:Strict、Lax、None SameSite=Lax(默认现代浏览器行为)允许通过顶级导航(如点击链接)发送,禁止 POST 表单跨站发送
Priority 低优先级 Cookie 可能被浏览器优先清除 Priority=High

三、Cookie 的作用域

  • 浏览器发送 Cookie 的规则(必须同时满足):
    • 域名匹配:如果 Domain 显式设置,则请求的域名必须与该 Domain(或其子域)完全匹配;如果未设置 Domain,则只对当前设置的域名(不含子域)发送。如:在 login.example.com 设置 Cookie 且未指定 Domain,则 api.example.com 不会收到该 Cookie。
    • 路径匹配:请求的 URL 路径必须是 Cookie Path 或其子路径,例:Path=/app 的 Cookie,在请求 /app/user 时会发送,但请求 /admin 时不发送。
    • 协议匹配(Secure 属性):带 Secure 的 Cookie 只在 HTTPS 请求中发送。
    • SameSite 校验;
    • 未过期(Expires / Max-Age)。

四、Cookie 的实际使用场景

① 用户登录(会话管理)
  • 用户 POST 用户名密码 → 服务器验证成功 → 生成一个随机的 sessionId → 通过 Set-Cookie 下发(HttpOnly; Secure; SameSite=Lax);
  • 后续请求浏览器自动携带该 Cookie → 服务器根据 sessionId 查到用户信息 → 保持登录状态。
② 记住"7 天免登录"
  • 登录时勾选"记住我" → 服务器除了下发会话 Cookie,再设置一个 remember_token,Max-Age=604800(7天);
  • 下次访问时,若会话过期但 remember_token 有效,服务器自动重建会话。
③ 记录用户偏好(如主题颜色)
  • 用户点击"深色模式" → JS 执行 document.cookie = "theme=dark; max-age=31536000; path=/";
  • 下次访问时,JS 读取 document.cookie 中的 theme 值,直接应用深色模式(无需请求服务器)。
④ 购物车(未登录状态)
  • 用户添加商品时,前端将商品 ID 和数量存入 Cookie(如 cart=[{"id":1,"qty":2}] 编码后);
  • 结账时,JS 读取 Cookie 中的购物车数据发给服务器;
  • 缺点:Cookie 大小受限,只适合少量商品;登录后可迁移到服务端存储。
⑤ A/B 测试分组
  • 用户首次访问时,服务器随机分配一个分组(如 group=A)并设置 Cookie,有效期 1 个月;
  • 后续该用户始终看到 A 版本的界面,保证实验一致性。

五、Cookie 的生成、读取、修改、删除

  • 服务器端生成(最常用),通过 HTTP 响应头 Set-Cookie 下发,Node.js (Express) 示例:
swift 复制代码
res.cookie('username', 'Alice', { maxAge: 900000, httpOnly: true, secure: true });
  • 客户端通过 JavaScript 生成(不常用,且受 HttpOnly 限制),设置的 Cookie 无法加 HttpOnly,且不能跨域:
swift 复制代码
document.cookie = "color=blue; path=/; max-age=86400";
  • 读取 Cookie:
    • 服务端:通过 HTTP 请求头 Cookie 获取;
swift 复制代码
Cookie: sessionId=abc123; color=blue
    • 客户端 JS:console.log(document.cookie) 得到所有非 HttpOnly 的 Cookie,以分号分隔的字符串。
  • 修改 Cookie:使用相同的 Name、Domain、Path 重新设置一次即可覆盖旧值:
swift 复制代码
// 修改名为 color 的值
document.cookie = "color=red; path=/";
  • 删除 Cookie,设置过期时间为过去的时间:
swift 复制代码
document.cookie = "color=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/";
  • 客户端是可以修改 Cookie 的,因为 Cookie 就存储在用户自己的浏览器里,用户有完全的控制权。
  • 可以通过浏览器开发者工具修改:
    • 按 F12 打开开发者工具 → 选择 Application(或"存储")标签 → 左侧找到 Cookies → 选中当前网站;
    • 你会看到所有 Cookie 的列表(名称、值、域名、路径等);
    • 双击"值"那一列直接编辑,或者新增/删除。
  • 通过 JavaScript(前提是 Cookie 没有设置 HttpOnly 属性):
swift 复制代码
// 查看所有 cookie
console.log(document.cookie);

// 修改一个 cookie(直接覆盖)
document.cookie = "username=newValue; path=/";

// 添加新 cookie
document.cookie = "theme=dark; max-age=3600";

// 删除 cookie(设置过期时间为过去的时间)
document.cookie = "username=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/";
  • 如果服务器在设置 Cookie 时加了 HttpOnly 标记,那么 document.cookie 是读不到也改不了这个 Cookie 的(目的是防止 XSS 攻击)。但用户依然可以通过开发者工具直接修改它,因为那是浏览器提供的原生界面。

七、Cookie 可以实现跨域访问吗?

  • 默认情况是不可行的:Cookie 遵循同源策略,即一个域(如 a.com)设置的 Cookie 只能被 a.com 的请求自动携带,不会发给 b.com,这是出于安全考虑。
  • 但有限条件下可以,可以实现"跨域"访问:
    • 真正不同域之间的跨域(比如 a.comb.com 发请求时携带 Cookie),需要同时满足三个条件:
      • 服务器在设置 Cookie 时加上 SameSite=None 和 Secure(必须 HTTPS)。
      • 前端发起请求时(比如用 fetch 或 XMLHttpRequest)加上 credentials: 'include' 选项。
      • 目标服务器(b.com)的响应头中必须包含 Access-Control-Allow-Origin(且值不能是 *,必须是明确的 a.com 或具体域名)以及 Access-Control-Allow-Credentials: true。
    • 这种方式有安全风险(CSRF),现代浏览器限制很严格,一般仅用于受信任的服务之间。

八、Cookie 的其他常见问题

  • Cookie 中能不能存储中文? Cookie 可以存储中文,但最好进行 encodeURIComponent 编码,避免分号、逗号等特殊字符问题:
swift 复制代码
document.cookie = `name=${encodeURIComponent('张三')}; path=/`;
  • 如何让 Cookie 只在当前浏览器会话有效? 不设置 Expires 和 Max-Age 即可(会话级 Cookie)。
  • 删除一个 Cookie 时为什么必须指定 Path 和 Domain? 因为 Cookie 是通过 Name + Domain + Path 三元组唯一标识的,如果不提供相同的 Domain 和 Path,浏览器会认为是在设置一个不同的 Cookie(而非删除目标 Cookie)。假设原 Cookie 有 Path=/app),可能删不掉,如下所示的错误示例:
swift 复制代码
document.cookie = "color=; expires=..."
  • 如何防止 Cookie 被 CSRF 读取(但 CSRF 不需要读取,只需要利用)? 设置 SameSite=Lax 或 Strict,Lax 允许从外部链接进入时携带,但禁止 POST 表单等跨站请求携带,能防御绝大部分 CSRF。
  • Cookie 的 Max-Age 和 Expires 同时出现时哪个优先? 现代浏览器中 Max-Age 优先,如果两者都未设置,则为会话级。
相关推荐
木斯佳2 小时前
前端八股文面经大全:腾讯前端一面(2026-04-04)·深度解析
前端·ai·鉴权·monorepo
code_Bo2 小时前
kiro生成小程序商业案例
前端·微信小程序·小程序·云开发
yellowbuff2 小时前
为什么你的 0.01 秒倒计时看起来一卡一卡的?
前端
Never_Satisfied2 小时前
安全属性标志详解:HTTPOnly
安全
onebyte8bits2 小时前
NestJS 系列教程(十八):文件上传与对象存储架构(Multer + S3/OSS + 访问控制)
前端·架构·node.js·状态模式·nestjs
无名的小三轮2 小时前
nmap使用手册
安全
Ruihong2 小时前
放弃 Vue3 传统 <script>!我的 VuReact 编译器做了一次清醒取舍
前端·vue.js
weixin_456164832 小时前
vue3 父组件向子组件传参
前端
Beginner x_u2 小时前
前端八股整理|CSS|高频小题 01
前端·css·八股