如何防止node.js应用程序中的会话溢出?

问题描述:

我有一个使用快速框架的nodejs web应用程序,它可以通过互联网到达。 我正在使用将会话存储为磁盘上的纯文件的会话存储,并且对于当前实现,每个没有cookie的请求都将获得新的会话ID,从而导致新会话磁盘上的新文件。如何防止node.js应用程序中的会话溢出?

由于应用程序是通过互联网访问,我收到很多无效的请求,这当然从来没有在我的文件系统,这是一个真正的混乱发送cookie,但产生更多的会话。

我使用OWASP会话管理备忘单作为实施指南(https://www.owasp.org/index.php/Session_Management_Cheat_Sheet),但未包括访客会话的详细主题。它只说明应用程序可能会发现将会话也分配给未经身份验证的(来宾)用户很有用,因此访客会话似乎总体上是有效的功能。

所以现在我不知道如何正确地解决无效/恶意请求造成的不必要的会话/会话文件问题。有没有推荐的方法来做到这一点?
我想也许是一个非常短的'客人'会话到期(< 5分钟)和IP范围的白名单或某事的组合,其中任何IP不在白名单中都不会收到访客会话(当然,但当然会话一旦成功认证)。

关于我该如何解决这个问题的任何提示?

+0

为什么你认为在纯文件中创建和存储会话是安全的方式?会话最好存储在标有过期日期的内存/缓存服务器中。此外,如果您收到很多无效请求,请尝试限制IP或者甚至禁止某些IP。无论哪种方式,我相信你正在推翻它,并增加许多预防措施,使你的应用程序无法维护。尝试使用像头盔这样的模块并阅读有关确保快速应用的文章 – Gntem

不管你如何存储你的会话,你将面临同样的问题。在某个时候,你的会话存储将会溢出(磁盘空间不足,内存耗尽,inode等耗尽)。

你需要做的是修剪你的会话。除非您真的可以负担无限期地存储会话,否则应该在会话cookie上设置到期日期。对于客户端浏览器将负责删除cookie。对于服务器,您需要定期检查所有会话以查看是否有任何已过期。

接下来你做什么很简单。无论您选择存储会话的技术如何,您都可以简单地删除过期的会话。这可以在您的节点进程内(在某些setTimeout()处理程序内)或在您的节点进程外(可能是简单的每日cron作业)完成。

在删除陈旧的会话文件之前,您应该允许一些宽限期(1分钟,1小时,1天等),以防止删除会话文件和加载网站的用户之间的竞争状态。

您可能还希望允许用户在每次访问时刷新会话过期日期。对于基于文件的会话存储,这可以像触摸文件以更新上次修改时间一样简单。

有一种情况是这种策略不起作用。由于性能原因(例如,InnoDB,MySQL)删除数据时,某些数据库不会释放磁盘空间。相反,数据只是标记为已删除,但数据库不断增长。在这种情况下,你唯一的出路就是改变会话存储。但是由于您使用的是文件存储,因此您不必担心这个问题。

+0

你在这里得到了一些好点。根据OWASP的要求(空闲超时,绝对超时,自动更新),我已经有会话超时和循环检查。它将根据这些超时删除会话。但是应用程序需求包括经过身份验证的用户会话的相当长的使用期限,因此,访客会话当前也受到影响。 也许我应该引入访客会话的单独(短暂)超时,并且不要将访客会话存储为持久性。 – user826955

+0

@ user826955:是的,就是这样做的。一旦您的网站变得流行,通常没有登录的用户将远远超过登录用户。特别是一旦你的网站被谷歌索引。如果你使用谷歌,它会被其他爬虫抓取。至少会有必应,雅虎和百度 – slebetman

为您的使用情况是Redis的,Memcached的或其他一些快速内存数据存储,但请注意,所有的会话数据将不得不适应RAM的最佳会话存储。

另一种选择是使用基于磁盘的数据库,如任何RDBMS或Mongo,Couch,Rethink等,但要确保速度很快,否则你的性能将大大降低。

与最高的可扩展特性,最快的方式是不要任何会话数据存储在服务器上,而是依赖于饼干或其他客户端存储,例如发送的数据使用JWT - 请参阅:https://jwt.io/ - 但请注意,通过这种方式,您将无法控制一次发布的会话令牌,除非您引入数据库来检查它们是否有效以及使其无效的机制,但此时您具有相同的就像在服务器上存储数据一样,可能存在的问题是可能存储的数据可能更少,并且不需要经常更新。

这里的每一个方法都有优点和缺点,但存储在文件系统中的文件数据是从来没有生产的最佳解决方案的任何数据,不仅为会话数据。如果你的用例中的缺点是可以接受的,你应该使用一个数据库或者在客户端存储数据。

+0

正如你已经提到的那样,正如@slebetman所提到的,存储技术是无关紧要的,因为任何可能的技术都会在某些时候溢出。 我想坚持服务器端会话存储,因为这是(至少对于我的理解/研究/知识)更安全,也是OWASP推荐的。 – user826955

这是要避免的事情:

app.use(session({ ... })); 
app.use(express.static(...)); 

这将创造所有静态请求会话。

您可以减轻通过禁用saveUninitialized setting

app.use(session({ 
    saveUninitialized : false, 
    ... 
})); 
app.use(express.static(...)); 

这将阻止新的,但是非修饰会话存储。由于静态资源不会修改会话,因此不会为其创建会话。

另一种选择是,以使会议的只有你的路由的子集:

const session = require('express-session'); 

let sessionMiddleware = session({ ... }); 

app.use('/api', sessionMiddleware, apiRouter); 
+0

虽然我正在使用会话管理的自定义实现(并没有按照公司的要求提供表达式中间件),但我喜欢不会将访客会话刷新到存储的想法,而只是将其保存在内存中。大概这可以与@slebetman提到的想法一起解决。 – user826955

+0

@ user826955不保存在请求生命周期内未被修改的新会话的想法可能会帮助您节省大量文件I/O。 – robertklep