cookie-session设置req.session=null后浏览器Cookie未清除的问题
根据cookie-session官方文档,销毁会话可通过req.session = null实现。在NestJS应用中,我通过@Session()装饰器获取会话并为其赋值userId属性:
@Post('/signin') @Serialize(UserDto) async signin(@Body() body: SigninUserDto, @Session() session: any) { const user = await this.authService.signin(body); session.userId = user.id; return user; }
此操作会在浏览器中创建会话Cookie:
但执行登出操作时,我按照文档将session设为null,浏览器中的会话Cookie却仍可见:
@Post('/signout') @UseGuards(AuthGuard) @Serialize(UserDto) signout(@Session() session: any) { session = null; }
补充说明:前端使用NextJS实现基础登录表单,登录后跳转至带登出按钮的首页,点击按钮会调用NestJS的登出接口执行session=null操作。
请问:
- 浏览器中会话Cookie仍可见的原因是什么?
- 是否存在安全隐患?
- 如何彻底清除会话?
原因:局部变量赋值未修改真实会话对象
你在登出方法里直接给session局部变量赋值null,这只是改变了变量本身的引用,并没有触碰到req.session这个真实的会话对象。NestJS的@Session()装饰器注入的是req.session的引用,但直接给局部变量赋值不会影响原对象,所以cookie-session没有触发销毁会话的逻辑,浏览器里的Cookie自然不会被清除。
安全隐患:存在身份验证失效风险
虽然浏览器里还能看到Cookie,但如果会话数据没被正确销毁,用户执行登出后,后续请求可能仍携带有效会话,导致登录状态无法正常清除。另外,残留的Cookie可能被攻击者尝试利用,虽然多数情况下无效,但仍存在潜在的伪造请求风险。
彻底清除会话的正确方法
必须直接修改req.session为null,而不是局部变量。可以通过@Request()装饰器获取完整的请求对象来操作:
import { Request } from 'express'; @Post('/signout') @UseGuards(AuthGuard) @Serialize(UserDto) signout(@Request() req: Request) { req.session = null; }
这样操作后,cookie-session会自动在响应头中添加Set-Cookie指令,将会话Cookie的过期时间设为过去的时间,浏览器收到后就会自动清除该Cookie。
如果需要更手动的方式,也可以直接清除Cookie:
import { Response } from 'express'; @Post('/signout') @UseGuards(AuthGuard) signout(@Response() res: Response) { res.clearCookie('session'); // 替换成你的会话Cookie实际名称 res.status(200).send({ message: '登出成功' }); }
注意使用@Response()时需要手动发送响应,否则请求会一直挂起。
内容的提问来源于stack exchange,提问作者JustinD

