---
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令牌协同。
二、策略基线与参数
- 必选属性:
Secure、HttpOnly、SameSite=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')
}
七、校验清单与验收
Secure与HttpOnly始终开启,SameSite默认Lax,敏感场景验证Strict。- 会话ID长度≥32字节并为不可预测随机数;登录与权限提升后执行滚动。
- 作用域使用
__Host-前缀,Path=/,禁止设置Domain以避免子域泄露。 - CSRF令牌长度与格式校验,头与体必须一致;跨站场景采用令牌而非放宽
SameSite。 - TTL不超过
86400并可按风险分级缩短;注销时立即回收并删除相关Cookie。

发表评论 取消回复