使express.js中的所有单个用户会话无效 [英] Invalidating all of a single user's sessions in express.js

查看:75
本文介绍了使express.js中的所有单个用户会话无效的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

出于安全原因,我们希望能够使用户的所有活动会话均无效,例如,如果他们更改了密码,或者只是希望能够强制注销其他会话.我们正在使用Node.js,Express,express-sessions和Redis会话存储.在我们的应用中,我们有(CoffeeScript):

For security reasons we want to be able to invalidate all of a user's active sessions, for example if they change their password, or just want to be able to force log out their other sessions. We're using Node.js, Express, express-sessions and the Redis session store. In our app we have (CoffeeScript):

app.use express.session
    cookie:
        maxAge: 5 * 24 * 60 * 60 * 1000 # 5 days in ms
    store: new RedisStore(client: rclient)
    key: "secret-key"

Redis存储通过将唯一的会话ID映射到您存储在会话中的任何数据来工作.例如:

The Redis store works by mapping the unique session id to whatever data you store in the session. For example:

# In an HTTP request
req.session.user = { _id: "user-id" }

在Redis中变为:

> get "sess:<session-id>"
'{ "user": { "_id": "user-id" } } '

我们需要的是一种跟踪与每个用户ID对应的所有会话的方法,以便在我们希望使用户的会话无效时可以将它们从Redis中删除.需要注意以下几点:

What we need is a way to track all sessions that correspond to each user id, so that we can remove these from Redis if we want to invalidate a user's sessions. The following caveats apply:

  1. 在Redis中为会话赋予TTL,该TTL等于 曲奇饼.每个会话的跟踪机制也应该过期 在这段时间之后,以避免过时的数据.
  2. 并非所有会话都必须与用户相关联.有些只是用来跟踪匿名会话的详细信息.
  1. The sessions are given a TTL in Redis equal to the maxAge of the cookie. The tracking mechanism for each session should also expire after this time to avoid stale data.
  2. Not all sessions will necessarily be associate to a user. Some are just used to track anonymous session details.

涉及警告(1)时,在Redis中添加另一个反向查找键(例如将user_id映射到用户的一组会话ID)的幼稚方法失败.

The naive approach of adding another reverse look up key in Redis (for example mapping user_id to a set of session ids for the user) fails when it comes to caveat (1).

这是其他使用Express的站点必定遇到的问题,因为这是一种非常常见的安全模式.有人对如何跟踪用户会话然后按需使用户会话无效有任何建议吗?

This feels like a problem that other sites using Express must have encountered, since it's a very common security pattern. Does anyone have any suggestions for how to track the user sessions and then invalidate them on demand?

谢谢!

推荐答案

在类似情况下,我要做的是使用自定义会话ID,该ID在密钥名称中包含用户ID.也许现在有一种更简单的方法可以做到这一点,但是基本上这是我设置自定义会话ID所要做的:

What I did for a similar situation is to use a custom session ID that includes the user id in the key name. Maybe there's an easier way to do this now, but here's basically what I had to do to set a custom session id:

main.js:

var uid = require('uid'),
    redis = require('redis'),
    session = require('express-session'),
    RedisStore = require('connect-redis')(session),
    Session = session.Session,
    Cookie = session.Cookie;

var utils = require('./utils');

var COOKIE_SECRET = 'somethingrandom',
    COOKIE_KEY = 'mycustomsession';

var redisClient = redis.createClient(),
    redisStore = new RedisStore({
      client: redisClient,
      ttl: 24 * 60 * 60, // 1 day session expiration
      prefix: 'sess:'
    });

// ... then inside the login route after user was successfully authenticated ...
req.sessionStore = redisStore;
req.sessionID = 'sess:' + user.id + ':' + uid(24);
req.session = new Session(req);
req.session.cookie = new Cookie({});
req.session.user = user;
utils.createSession(req, res, COOKIE_KEY, COOKIE_SECRET);

utils.js:

var onHeaders = require('on-headers'),
    signature = require('cookie-signature');
exports.createSession = function(req, res, name, secret) {
  var trustProxy = true;
  // ripped from express-session
  onHeaders(res, function() {
    if (!req.session)
      return;

    var cookie = req.session.cookie
      , proto = (req.headers['x-forwarded-proto'] || '').split(',')[0].toLowerCase().trim()
      , tls = req.connection.encrypted || (trustProxy && 'https' == proto);

    // only send secure cookies via https
    if (cookie.secure && !tls)
      return;

    var val = 's:' + signature.sign(req.sessionID, secret);
    res.cookie(name, val, cookie.data);
  });

  // proxy end() to commit the session
  var end = res.end;
  res.end = function(data, encoding) {
    res.end = end;
    if (!req.session) return res.end(data, encoding);
    req.session.resetMaxAge();
    req.session.save(function(err) {
      if (err) console.error(err.stack);
      res.end(data, encoding);
    });
  };
};

这篇关于使express.js中的所有单个用户会话无效的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆