Nodejs cluster模块和express一起用的话如何保持csrf值呢?

Nodejs cluster模块和express一起用的话如何保持csrf值呢?

如果是单进程的话req.session._csrf是不会变,但如果在多进程下这个req.session就不那么安分了,会随时刷新…

8 回复

当使用 Node.js 的 cluster 模块与 Express 一起工作时,你可能会遇到会话(session)和 CSRF 令牌在多个工作进程中不一致的问题。这是因为默认情况下,每个工作进程都有自己的会话存储,这会导致 CSRF 令牌在不同请求之间不一致。

为了解决这个问题,我们需要确保所有工作进程共享同一个会话存储。常用的解决方案是使用 Redis 来存储会话数据,这样所有的工作进程都可以访问相同的会话数据。

以下是一个简单的示例,展示了如何配置 cluster 模块、Express 和 Redis 来共享会话数据:

安装依赖

首先,安装必要的依赖包:

npm install express redis connect-redis express-session csrf

配置 Express 和 Redis

接下来,配置 Express 应用程序以使用 Redis 存储会话数据:

const express = require('express');
const session = require('express-session');
const RedisStore = require('connect-redis')(session);
const csrf = require('csurf');
const app = express();
const port = process.env.PORT || 3000;

// 使用 Redis 存储会话数据
app.use(session({
  store: new RedisStore(),
  secret: 'your-secret-key',
  resave: false,
  saveUninitialized: false
}));

// 初始化 CSRF 中间件
const csrfProtection = csrf({ cookie: true });

app.get('/', csrfProtection, (req, res) => {
  res.send(`
    <form action="/process" method="POST">
      <input type="hidden" name="_csrf" value="${req.csrfToken()}">
      <button type="submit">Submit</button>
    </form>
  `);
});

app.post('/process', csrfProtection, (req, res) => {
  res.send('Data received');
});

app.listen(port, () => {
  console.log(`Server is running on http://localhost:${port}`);
});

配置 Cluster 模块

最后,配置 cluster 模块以创建多个工作进程:

const cluster = require('cluster');
const os = require('os');

if (cluster.isMaster) {
  const numWorkers = os.cpus().length;
  console.log(`Master cluster setting up ${numWorkers} workers...`);

  for (let i = 0; i < numWorkers; i++) {
    cluster.fork();
  }

  cluster.on('exit', (worker, code, signal) => {
    console.log(`Worker ${worker.process.pid} died`);
  });
} else {
  // Worker processes have a copy of the server application
  require('./app'); // 引入你的 Express 应用
}

通过以上步骤,你可以确保在使用 cluster 模块和 Express 时,CSRF 令牌在整个应用程序中保持一致。


不是很懂……

放memecha之类的里面

不知道express的csrf实现, 不过其实可以放到浏览器cookie里 设置成http-only 客户端取不到就行

hack下req对象 _csrf直接从cookie里取就行了

sessionStore 设置成 mongodb , redis 这种应该就可以了吧

我试试

待我试一试,原来用过mongodb来存session,但有个小问题,session里数据变化不一定都是准确的,一次请求中我把一个数字减1,下次请求还是原来的样子,这个问题也困扰我很久…

当使用 Node.js 的 cluster 模块与 Express 框架一起时,共享会话数据可能会成为一个挑战。这是因为每个工作进程都有自己的内存空间,导致同一个用户的请求可能被分配到不同的工作进程中,从而使得会话数据无法保持一致。

为了解决这个问题,你可以使用一个支持分布式会话存储的中间件,比如 express-session 结合 connect-redisconnect-mongo 等持久化存储方案来保存会话数据。这样可以确保即使用户请求被分发到不同的工作进程,他们仍然可以访问到相同的会话数据。

以下是一个使用 express-sessionconnect-redis 来保持 CSRF 值一致性的示例:

const express = require('express');
const session = require('express-session');
const RedisStore = require('connect-redis')(session);
const csrf = require('csurf');
const app = express();

app.use(session({
    store: new RedisStore(), // 使用 Redis 存储会话
    secret: 'your-secret-key',
    resave: false,
    saveUninitialized: false,
}));

app.use(csrf({ cookie: true })); // 初始化 CSRF 中间件

app.get('/', (req, res) => {
    res.send(`
        <form action="/process" method="post">
            <input type="hidden" name="_csrf" value="${req.csrfToken()}">
            <button type="submit">Submit</button>
        </form>
    `);
});

app.post('/process', (req, res) => {
    res.send('Form processed!');
});

app.listen(3000, () => console.log('Server is running on port 3000'));

在这个例子中,我们首先创建了一个 Express 应用,并使用 express-session 设置了一个 Redis 存储会话。接着,我们通过 csurf 中间件处理 CSRF 保护。由于所有工作进程都共享相同的 Redis 数据库,所以它们可以访问相同的会话数据,从而保持 CSRF 值的一致性。

要运行此应用,你需要安装必要的依赖包:

npm install express express-session connect-redis csurf

然后启动你的 Node.js 应用。

回到顶部