如何在每次刷新页面时验证会话 cookie 的完整性,应该这样做吗?

Posted

技术标签:

【中文标题】如何在每次刷新页面时验证会话 cookie 的完整性,应该这样做吗?【英文标题】:How to validate the integrity of session cookie on each page refresh, and should one? 【发布时间】:2020-01-05 05:38:49 【问题描述】:

我在我的应用程序上设置了 PassportJS 身份验证,其中包含 Facebook、Twitter 和 Google 以及本地策略。这是我目前的身份验证路线的样子:

// /routes/auth-routes.js

import connectRedis from 'connect-redis';
import express from 'express';
import session from 'express-session';
import uuidv4 from 'uuid/v4';

import facebook from './auth-providers/facebook';
import google from './auth-providers/google';
import local from './auth-providers/local';
import twitter from './auth-providers/twitter';

const RedisStore = connectRedis(session);
const router = express.Router();

router.use(session(
  name: process.env.SESSION_COOKIE,
  genid: () => uuidv4(),
  cookie: 
    httpOnly: true,
    sameSite: 'strict',
  ,
  secret: process.env.SESSION_SECRET,
  store: new RedisStore(
    host: process.env.REDIS_HOST,
    port: process.env.REDIS_PORT,
    ttl: 1 * 24 * 60 * 60, // In seconds
  ),
  saveUninitialized: false,
  resave: false,
));

// Social auth routes
router.use('/google', google);
router.use('/twitter', twitter);
router.use('/facebook', facebook);
router.use('/local', local);

// Logout
router.get('/logout', (req, res) => 
  req.logout();
  const cookieKeys = Object.keys(req.cookies);
  if(cookieKeys.includes(process.env.USER_REMEMBER_COOKIE)) 
    console.log('REMEMBER COOKIE EXISTS!');
    const rememberCookie = process.env.USER_REMEMBER_COOKIE;
    const sessionCookie = process.env.SESSION_COOKIE;
    cookieKeys.forEach((cookie) => 
      if(cookie !== rememberCookie && cookie !== sessionCookie) res.clearCookie(cookie);
    );
    res.redirect(req.query.callback);
   else 
    console.log('NO REMEMBER');
    req.session.destroy(() => 
      cookieKeys.forEach((cookie) => 
        res.clearCookie(cookie);
      );
      res.redirect(req.query.callback);
    );
  
);

module.exports = router;

显然,我使用 Redis 来存储会话 cookie,然后在每次页面重新加载时将其与所有其他 cookie 一起发送到服务器。这是我的问题:

这就够了吗?我不应该通过在 Redis 存储中查找接收到的会话 cookie 来验证它的完整性吗?但是,如果我在每次页面加载时都这样做,那不会对性能产生不利影响吗?处理这个问题的标准方法是什么?

回购位于https://github.com/amitschandillia/proost/blob/master/web。

【问题讨论】:

Redis 存储保存所有会话数据,cookie 通常只是会话 ID。所以每个请求都已经在 Redis 存储中查找过了。 如果在存储中查找每个请求,如果未找到匹配项会发生什么情况,即 cookie 已被更改或完全删除?它会返回某种标志,然后我可以在我的路线中使用吗?我尝试了 PassportJS isAuthenticated() 方法,但无论登录状态如何,它似乎都会返回 false 【参考方案1】:

您似乎缺少通过 express-session 与 PassportJS 集成的部分内容。就像前面提到的评论一样,express-session 会将你的 session 数据存储在 redis store 中,它的 key 会存储在发送给用户的 cookie 中。

但是您通过passportJS 登录您的用户,您需要将这两个中间件连接在一起。来自 passportJS 文档:

http://www.passportjs.org/docs/configure/

中间件

在基于 Connect 或 Express 的应用程序中,需要使用 passport.initialize() 中间件来初始化 Passport。如果您的应用程序使用持久登录会话,则还必须使用 passport.session() 中间件。

app.configure(function() 
  app.use(express.static('public'));
  app.use(express.cookieParser());
  app.use(express.bodyParser());
  app.use(express.session( secret: 'keyboard cat' ));
  app.use(passport.initialize());
  app.use(passport.session());
  app.use(app.router);
);

【讨论】:

我没有遗漏任何这些部分,您可以在 GitHub 上查看自己的代码。 Passport 在其文档中的任何地方都没有提到如果会话不匹配它会做什么。它会返回一个标志吗?它拒绝登录吗?没有。它继续登录,好像会话无关紧要。

以上是关于如何在每次刷新页面时验证会话 cookie 的完整性,应该这样做吗?的主要内容,如果未能解决你的问题,请参考以下文章

清除cookie并强制每次用户访问网站时登录?

jQuery实现发送验证码30s倒计时,且刷新页面时有效

MVC 身份验证超时/会话 cookie 删除后的 Ajax 请求

修复 laravel 5 会话在刷新或进入另一个页面后过期?

每次刷新或访问页面时,Node js express-session都会创建新的会话ID

如何防止 Laravel 中的会话/cookie 刷新?