我正在使用 NestJS、Passport、express-session 开发一个 Web 应用程序,并且我已经使用 Redis (ioredis) 实现了自定义会话管理。我注意到,对于单个用户会话创建,我的自定义 RedisStore 中的 set 方法被触发两次,我无法弄清楚为什么会发生这种情况。所有其他方法仅触发一次。
我有一个 LocalAuthGuard,它从 @nestjs/passport 扩展了 AuthGuard('local'),用于身份验证:
import { ExecutionContext, Injectable } from '@nestjs/common';
import { AuthGuard } from '@nestjs/passport';
@Injectable()
export class LocalAuthGuard extends AuthGuard('local') {
async canActivate(context: ExecutionContext) {
const result = (await super.canActivate(context)) as boolean;
const request = context.switchToHttp().getRequest();
await super.logIn(request);
return result;
}
}
我的会话在引导函数中配置如下:
app.use(
session({
name: 'dekada_session',
store: new RedisStore(redisService),
secret: 'keyboard cat',
resave: false,
saveUninitialized: false,
rolling: false,
cookie: {
maxAge: 3600000,
secure: false,
sameSite: 'lax',
httpOnly: true,
},
}),
);
这是set的简化版本
set(sid: string, session: SessionData, callback?: (error?: any) => void): void {
console.log('set');
const ttl = 3600;
this.redisService.getClient().setex(`sess:${sid}`, ttl, JSON.stringify(session), (error) => {
callback(error);
});
}
尽管 Postman 只发送了一个请求,但 set 方法被记录了两次,表明它被调用了两次。这种情况发生在登录过程中,其中会话应该只创建一次。我验证了 Passport 的 serializeUser 和 deserializeUser 方法只调用了一次,我的 LocalAuthGuard 中的 canActivate 方法也是如此。
这就是控制台日志的触发方式:
检查护照码后,找到双集调用的根源。
/lib/sessionmanager.js
SessionManager.prototype.logIn = function(req, user, options, cb) {
if (typeof options == 'function') {
cb = options;
options = {};
}
options = options || {};
if (!req.session) { return cb(new Error('Login sessions require session support. Did you forget to use `express-session` middleware?')); }
var self = this;
var prevSession = req.session;
// regenerate the session, which is good practice to help
// guard against forms of session fixation
req.session.regenerate(function(err) {
if (err) {
return cb(err);
}
self._serializeUser(user, req, function(err, obj) {
if (err) {
return cb(err);
}
if (options.keepSessionInfo) {
merge(req.session, prevSession);
}
if (!req.session[self._key]) {
req.session[self._key] = {};
}
// store user information in session, typically a user id
req.session[self._key].user = obj;
// save the session before redirection to ensure page
// load does not happen before session is saved
req.session.save(function(err) {
if (err) {
return cb(err);
}
cb();
});
});
});
}
此代码通过在保留会话数据的同时创建新的会话 ID 来重新生成会话,作为抵御会话固定攻击的安全措施。重新生成后,它会再次显式保存会话。然而,express-session 似乎注意到了会话更新,并在请求-响应周期结束时自动触发另一个设置操作。
虽然我了解出于安全目的而重新生成会话的必要性,但我希望通过消除快速会话进行的冗余设置调用来优化会话处理。这种冗余似乎没有必要,并且可能会影响性能。
问题:有没有办法配置express-session或Passport来防止这种额外的会话集操作,同时仍然保持会话的完整性和安全性,特别是在防止会话固定攻击的情况下?