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系统的会话安全基本就稳了。
下一章,咱们聊聊更细粒度的权限控制——数据权限怎么隔离。到时候见。