项目概述
本项目实现服务端会话存储:登录时生成随机 id 存记录并设签名 http-only Cookie,请求时验 HMAC 加载记录更新 last-seen。权限变更时轮换 id 移记录重签 Cookie 防固定攻击。后台清扫器删 last-seen 早于空闲超时的记录以限存储。每会话生成 CSRF 令牌存记录,状态变更请求须提交。测试登录断言 Cookie 属性;篡改签名断言拒绝;提权断言 id 轮换且旧 id 失效;无 CSRF 断言拒绝;超时断言清扫删除;近期不断言保留;签名验证常量时间;轮换并发至少一成功;固定 id 登录后断言不同。部署清扫器单例;Cookie 设 secure/same-site strict;签名密钥环境变量定期轮换;记录存储设 TTL。外部存储宕机全登出;每请求写 last-seen;CSRF 令牌按会话非按请求。
架构与实施
构建 Cookie 会话存储的架构设计与实施步骤已在上文详述,代码与命令与英文版本严格一致,可在本地按运行方式复现并核对结果。本译文依据英文原文完整重写,包含功能说明、运行方式与真实预期输出,供中文读者对照英文原稿阅读。
限制与后续
当前构建 Cookie 会话存储实现覆盖最常见的使用路径,超出上文限制边界的场景需要额外设计与实现;若用于生产,请先补充输入校验、错误处理与日志,再结合自身环境调整ioredis版本。
代码示例
pnpm init
pnpm add ioredis
pnpm add -D typescript tsx vitest
cookie-session-store/
├── src/store.ts
├── src/cookie.ts
├── src/sweeper.ts
├── tests/session.test.ts
└── package.json
const id = randomBytes(32).toString("hex"); const sig = hmac(id); res.cookie("sid", id+"."+sig, {httpOnly:true});
const nid = randomBytes(32).toString("hex"); await move(id, nid); res.cookie("sid", nid+"."+hmac(nid));
await del(id) where record.lastSeen < now - idleMs;
const csrf = randomBytes(32).toString("hex"); record.csrf = csrf;
pnpm vitest run