You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

fastify-session结合postgres存储下的fastify-csrf实现问题咨询

问题1:CSRF token的生成时机

  • 既不需要每次请求都生成,也不需要严格限制仅在session cookie首次生成时生成。CSRF token和当前用户会话绑定,同一会话有效期内生成的所有token均合法。你可以根据安全需求选择:
    • 方案1:会话生命周期内仅生成一次,开发成本低,适合普通业务场景
    • 方案2:每次前端获取token时都重新生成,安全性更高,适合对安全要求高的业务

问题2:generateCsrf示例路由的适用范围

  • 不是仅能应用在/login路由上,所有需要给前端返回CSRF token的场景都可以调用该方法。比如单页应用可以单独做一个/api/get-csrf公共路由用于前端初始化时拉取token,也可以在首页、注册页、登录页等用户首次访问的路由返回token。

注意你当前配置的saveUninitialized: false会导致未初始化会话的用户无法生成CSRF token,如果你允许未登录用户提交表单/请求(比如注册、游客留言),需要把该配置改为true,或者在对应生成token的路由中手动初始化会话。

问题3:篡改校验的触发时机

  • Cookie篡改校验:你配置的secret参数会让fastify-session和fastify-cookie自动完成所有请求的cookie签名校验,校验失败会自动清除无效cookie,不需要你手动处理。
  • CSRF校验:需要你手动给所有非GET/HEAD/OPTIONS请求(即会修改服务端数据的请求)添加校验逻辑,有两种实现方式:
    • 全局添加preHandler钩子,排除不需要校验的路由(比如获取token的路由、登录页GET请求)
    • 给需要校验的路由单独添加csrfProtection: true配置

修正后的代码示例

你的原代码存在插件注册顺序错误:fastify-session需要注册在fastify-csrf之前,否则csrf无法读取会话数据,修正后代码如下:

const cookie = require('fastify-cookie');
const session = require('fastify-session');
const csrf = require('fastify-csrf');
const pgSession = require('connect-pg-simple')(session);
const fp = require('fastify-plugin');

/**
 * @param {import('fastify').FastifyInstance} fastify
 */
const plugin = async (fastify) => {
  fastify.register(cookie);
  // 先注册session,再注册csrf
  fastify.register(session, {
    store: new pgSession({
      conString: process.env.DATABASE_URL,
      tableName: 'user_session',
    }),
    secret: process.env.SESSION_SECRET,
    saveUninitialized: false, // 若需要支持游客态的CSRF校验请改为true
    cookie: {
      httpOnly: true,
      secure: process.env.NODE_ENV !== 'development',
      maxAge: 86400 * 1000,
      sameSite: 'lax' // 建议加上,进一步降低CSRF风险
    },
  });
  fastify.register(csrf, { sessionPlugin: 'fastify-session' });

  // 通用获取CSRF token的路由,前端初始化时调用即可
  fastify.route({
    method: 'GET',
    path: '/api/get-csrf',
    handler: async (req, reply) => {
      const token = await reply.generateCsrf();
      return { csrfToken: token };
    },
  });

  // 全局CSRF校验逻辑,自动校验所有非GET类请求
  fastify.addHook('preHandler', async (req, reply) => {
    // 排除不需要校验的请求
    if (['GET', 'HEAD', 'OPTIONS'].includes(req.method)) return;
    // 手动触发CSRF校验,校验失败会自动返回403
    await req.csrfProtection();
  });

  fastify.addHook('preHandler', (req, reply, next) => {
    if (req.session && !req.session.user) req.session.user = {};
    next();
  });
};

module.exports = fp(plugin);

内容的提问来源于stack exchange,提问作者user616

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.07 12:06:04