---

title: Cookie与会话安全策略统一落地(属性收敛与滚动)最佳实践

keywords:

  • Cookie
  • Session
  • HttpOnly
  • Secure
  • SameSite
  • CSRF
  • Rotation
  • Session Fixation
  • TTL
  • __Host-前缀
  • Domain
  • Path

description: 统一会话安全基线与可验证的落地方案,包含Cookie属性收敛(Secure/HttpOnly/SameSite、精确Path/Domain)、登录后会话ID滚动与TTL策略、CSRF令牌、设备指纹绑定与注销回收,附服务端设置与校验示例。

categories:

  • 文章资讯
  • 技术教程

---

一、风险背景与目标

  • 风险:会话固定(Session Fixation)、CSRF跨站请求、XSS读取Cookie、子域泄露与范围过宽、持久会话未轮换。
  • 目标:属性收敛最小化权限、会话登录与敏感操作后滚动ID、精确路径与域名作用域、SameSite控制与CSRF令牌协同。

二、策略基线与参数

  • 必选属性:SecureHttpOnlySameSite=Lax;敏感场景可设Strict
  • 作用域:优先使用__Host-前缀,Path=/且不设置Domain
  • TTL与持久化:建议Max-Age≤86400,并在登录后、权限提升后执行会话ID滚动。
  • 注销与回收:统一删除会话与刷新黑名单,立即失效。

三、服务端设置与统一构造

type CookieOpt = { secure: boolean; httpOnly: boolean; sameSite: 'Lax' | 'Strict' | 'None'; path: string; domain?: string; maxAge?: number }
function buildCookie(name: string, value: string, opt: CookieOpt): string {
  const parts: string[] = []
  parts.push(`${encodeURIComponent(name)}=${encodeURIComponent(value)}`)
  parts.push(`Path=${opt.path}`)
  if (opt.domain) parts.push(`Domain=${opt.domain}`)
  if (opt.maxAge !== undefined) parts.push(`Max-Age=${opt.maxAge}`)
  parts.push(`SameSite=${opt.sameSite}`)
  if (opt.secure) parts.push('Secure')
  if (opt.httpOnly) parts.push('HttpOnly')
  return parts.join('; ')
}

type Res = { setHeader: (k: string, v: string | string[]) => void }

function setSessionCookie(res: Res, id: string, ttl: number) {
  const name = '__Host-session'
  const header = buildCookie(name, id, { secure: true, httpOnly: true, sameSite: 'Lax', path: '/', maxAge: ttl })
  res.setHeader('Set-Cookie', header)
}

function expireCookie(res: Res, name: string) {
  const header = buildCookie(name, '', { secure: true, httpOnly: true, sameSite: 'Lax', path: '/', maxAge: 0 })
  res.setHeader('Set-Cookie', header)
}

四、会话ID滚动与绑定

function randomId(): string {
  return Buffer.from(crypto.getRandomValues(new Uint8Array(32))).toString('hex')
}

type Session = { id: string; userId: string; uaHash: string; createdAt: number; ttl: number }

function rotateSession(old: Session): Session {
  return { id: randomId(), userId: old.userId, uaHash: old.uaHash, createdAt: Date.now(), ttl: old.ttl }
}

function bindUa(ua: string): string {
  return require('crypto').createHash('sha256').update(ua).digest('hex')
}

function verifyUa(session: Session, ua: string): boolean {
  return session.uaHash === bindUa(ua)
}

五、CSRF令牌与SameSite协同

function issueCsrf(): string {
  return require('crypto').randomBytes(16).toString('hex')
}

function setCsrfCookie(res: Res, token: string) {
  const header = buildCookie('__Host-csrf', token, { secure: true, httpOnly: false, sameSite: 'Strict', path: '/', maxAge: 3600 })
  res.setHeader('Set-Cookie', header)
}

function validateCsrf(headerToken: string | undefined, bodyToken: string | undefined): boolean {
  if (!headerToken || !bodyToken) return false
  return headerToken === bodyToken && /^[a-f0-9]{32}$/.test(headerToken)
}

六、登录流程与注销处理示例

type Req = { headers: Record<string, string | undefined>; body: any }

function onLogin(req: Req, res: Res, userId: string) {
  const ua = req.headers['user-agent'] || ''
  const s: Session = { id: randomId(), userId, uaHash: bindUa(ua), createdAt: Date.now(), ttl: 86400 }
  setSessionCookie(res, s.id, s.ttl)
  const csrf = issueCsrf()
  setCsrfCookie(res, csrf)
}

function onSensitiveAction(req: Req, res: Res, current: Session) {
  const next = rotateSession(current)
  setSessionCookie(res, next.id, next.ttl)
}

function onLogout(res: Res) {
  expireCookie(res, '__Host-session')
  expireCookie(res, '__Host-csrf')
}

七、校验清单与验收

  • SecureHttpOnly始终开启,SameSite默认Lax,敏感场景验证Strict
  • 会话ID长度≥32字节并为不可预测随机数;登录与权限提升后执行滚动。
  • 作用域使用__Host-前缀,Path=/,禁止设置Domain以避免子域泄露。
  • CSRF令牌长度与格式校验,头与体必须一致;跨站场景采用令牌而非放宽SameSite
  • TTL不超过86400并可按风险分级缩短;注销时立即回收并删除相关Cookie。

点赞(0) 打赏

评论列表 共有 0 条评论

暂无评论
立即
投稿

微信公众账号

微信扫一扫加关注

发表
评论
返回
顶部