3、会话管理:Token生成与验证、Session超时策略、防会话劫持措施

聊到OA系统的安全,会话管理绝对是个绕不开的核心话题。我见过太多项目,功能做得花里胡哨,结果会话这块一塌糊涂,被攻击者钻了空子。说白了,会话就是系统识别“你是谁”的那张通行证。这张证要是被偷了,整个系统就跟没锁门一样。

今天咱们就掰开揉碎,把Token怎么生成、Session怎么超时、怎么防劫持,一次性讲清楚。

3.1 Token生成与验证:别用简单拼接

Token这东西,很多人觉得不就是一串随机字符串吗?嗯,没那么简单。我早期做的一个项目,Token直接用“用户ID+时间戳”拼接,再Base64编码一下。结果呢?上线第三天就被安全团队打回来了——太容易被伪造。

正确的做法是什么?我建议用JWT(JSON Web Token)。它自带签名机制,能防篡改。来看一个标准的生成流程:

// 服务端生成Token示例(伪代码)
function generateToken(userId, role) {
    const header = {
        "alg": "HS256",
        "typ": "JWT"
    };
    const payload = {
        "sub": userId,
        "role": role,
        "iat": Math.floor(Date.now() / 1000),
        "exp": Math.floor(Date.now() / 1000) + 3600  // 1小时过期
    };
    const secret = "你的密钥,别硬编码在代码里";
    return jwt.encode(header, payload, secret);
}

这里有几个关键点,你想想看:

  • 密钥管理:密钥绝对不能写死在代码里。我习惯用配置中心或者环境变量,线上和线下用不同的密钥。
  • Payload别放敏感信息:JWT的Payload只是Base64编码,不是加密。放个用户ID、角色就够了,别把密码、手机号塞进去。
  • 签名算法别用none:我记得有个经典漏洞,攻击者把alg改成none,服务端就跳过验证了。一定要校验算法白名单。

验证环节:每次请求过来,服务端都要做三件事——验签名、验过期时间、验用户状态。我见过有人只验签名,不验过期,结果Token泄露后永久有效,那问题就大了。

3.2 Session超时策略:太短烦人,太长危险

Session超时时间怎么设?这是个平衡艺术。设太短,用户写个文档中途去接杯水,回来就要重新登录,体验极差。设太长,比如一整天,那万一用户忘了退出,别人用他电脑就能直接操作。

我个人习惯分场景处理:

场景 建议超时时间 理由
普通办公操作 30分钟无操作 兼顾安全与体验
审批、财务等敏感操作 15分钟无操作 降低风险窗口
移动端OA 7天(记住我) 手机常带,但需二次验证

这里有个坑,我曾经踩过:只设了Token过期,没做滑动续期。用户正用着呢,突然Token过期了,页面直接跳登录。后来我改成了“滑动窗口”策略——只要用户在操作,就自动续期,但续期不超过最大时长(比如8小时)。

小技巧:可以在前端加个“即将超时”的弹窗提醒,让用户选择是否继续。这样既安全,又不会突然打断工作。

3.3 防会话劫持措施:别让攻击者钻空子

会话劫持,说白了就是攻击者拿到了你的Token或Session ID,然后冒充你操作。怎么防?我总结了几个实战中必须做的点。

3.3.1 绑定客户端特征

别光验证Token本身。我建议把Token和客户端的某些特征绑定在一起。比如:

  • IP地址:如果Token在A地生成,突然从B地请求,直接拒绝。但注意,移动办公场景下IP会变,可以放宽到IP段。
  • User-Agent:浏览器版本、操作系统这些信息,可以作为辅助校验。攻击者很难完全伪造一致。
  • 设备指纹:更高级的做法,用Canvas指纹、WebGL指纹等,生成设备唯一标识。

我在项目中遇到过这样一个案例:某员工在咖啡厅连了公共WiFi,Token被中间人截获。但因为绑定了设备指纹,攻击者用自己电脑重放请求时,直接被拦截了。嗯,这就是绑定的价值。

3.3.2 使用HTTPS和Secure Cookie

这个不用多说了吧?所有会话相关的Cookie,必须设置Secure和HttpOnly属性。Secure保证只在HTTPS下传输,HttpOnly防止XSS脚本读取。

// 设置Cookie示例
Set-Cookie: session_id=abc123; Secure; HttpOnly; SameSite=Strict; Path=/

SameSite=Strict也很关键。它能防止CSRF攻击——别的网站发起的请求,不会带上你的Cookie。

3.3.3 定期更换Token

别一个Token用到底。我建议:

  • 每次敏感操作后换Token:比如修改密码、转账、审批大额单据。
  • 定期轮换:即使没有敏感操作,每2小时也强制换一次。
  • 登出时立即失效:服务端要维护一个黑名单,或者用Redis记录有效Token。

警告:千万不要把Token存在localStorage里!XSS攻击一打一个准。我见过有团队为了方便,把Token放localStorage,结果被一个反射型XSS全拿走了。正确的做法是放内存变量,或者用HttpOnly的Cookie。

3.4 实战中的避坑指南

最后,分享几个我亲身踩过的坑,希望能帮你少走弯路:

  • 我曾经在Token里放了用户的明文角色,结果被篡改后提权。后来改成只放角色ID,权限从服务端查。
  • 我曾经把Session超时设成24小时,结果员工离职后账号还能用。后来加了“账号状态变更时立即失效所有会话”的逻辑。
  • 我曾经忽略了Token的刷新机制,导致高并发下大量Token同时过期,系统瞬间卡死。后来用了双Token机制——短期Token(15分钟)+ 长期Refresh Token(7天)。

会话管理这件事,说难不难,说简单也不简单。核心就一句话:别信任任何客户端传来的东西,服务端必须做二次校验。你想想看,只要把Token生成、超时策略、劫持防护这三块做好了,OA系统的会话安全基本就稳了。

下一章,咱们聊聊更细粒度的权限控制——数据权限怎么隔离。到时候见。