【问题标题】:Express.js API w/ Next.js: csurf implementation带有 Next.js 的 Express.js API:csurf 实现
【发布时间】:2020-10-20 07:57:02
【问题描述】:

总结:

我有一个由几个单独的应用程序构建的完整网络应用程序:

  1. next.js 面向客户的应用和
  2. express.js 网络接口。
  3. 哦,我正在使用 nginx 作为反向代理来为这两者提供服务,不确定这是否会干扰,但似乎它不会干扰我。

除了一件事:gosh darn csurf 实现之外,一切都按预期运行得很好。我无法让它工作并且已经尝试过。所以,我在这里寻求帮助。

关于应用程序:

next.js 应用呈现面向客户的所有内容。它有一个自定义服务器,它只使用头盔和对我的 express.js Web api 的“get-user”请求来填充 req.user 并使用“user”对象响应我的 next.js 应用程序来呈现私人路线。

express.js web api 通过 http 管理用户会话(到目前为止运行良好),仅设置为 next.js 标头的安全 cookie,next.js 客户端包括这些用于对 express.js web api 的请求.

问题:

一切都很好,但是当我尝试在我的 express.js web api 中使用 npm 模块名称“csurf”为我的 next.js 面向客户的应用程序设置一个 csrf cookie 时,我无法让它工作。我已成功设置 csrf 标头并获取该值,然后我使用 redux 在商店中设置它。然后,当我尝试获取 csrftoken 并将其应用于客户端请求时,该请求被拒绝。

下面是简短的代码实现:

  • Express.js web api,csurf imp(csurf imp 被注释掉了,因为它不起作用,正在尝试使用 在所有 api 路由上)

   import './env';
   import express from 'express';
   import csrf from 'csurf';
   import cors from 'cors';
   import morgan from 'morgan';
   import cookieParser from 'cookie-parser';
   import bodyParser from 'body-parser';
   import helmet from 'helmet';
   import redis from 'redis';
   import connectRedis from 'connect-redis';
   import session from 'express-session';

   import * as configs from '../config';

   import authRouter from './routes/authentication';
   import userRouter from './routes/user';
   import { setupLocalAuth } from './middleware/auth.middleware';

   const RedisStore = connectRedis(session);
   const client = redis.createClient({ host: configs.REDIS_CLIENT_HOST });

   const port = process.env.PORT || 5000;

   const app = express();
   app.use(cors({ origin: configs.CORS_ORIGIN, credentials: true }));
   if (configs.IS_DEV) {
      app.use(morgan('dev'));
   }
   app.use(helmet());
   app.use(cookieParser());
   app.use(bodyParser.json({ limit: '50mb' }));
   app.use(bodyParser.urlencoded({ extended: true }));
   app.use(cookieParser());
   app.use(
      session({
        name: configs.SESSION_NAME,
        secret: configs.SESSION_SECRET,
        store: new RedisStore({ client }),
        saveUninitialized: false,
        resave: false,
        proxy: configs.IS_DEV ? false : true,
        cookie: {
          domain: configs.SESSION_COOKIE_DOMAIN,
          httpOnly: true,
          secure: configs.SESSION_SECURE,
          maxAge: 14 * 24 * 60 * 60 * 1000, // 14 days
        },
      }),
    );

    /// /////////////////////////////////////////////////////////////////////////////////////////////
    //
    //
    /// /////////////////////////////////////////////////////////////////////////////////////////////
    // app.use(csrf({ cookie: true }));
    // app.use(function(req, res, next) {
    //   const token = req.csrfToken();
    //   res.cookie('XSRF-TOKEN', token);
    //   // res.locals._csrf = token;
    //   // res.locals.csrfToken = token;
    //   next();
    // });

    if (!configs.IS_DEV) {
      app.set('trust proxy', 1);
    }

    setupLocalAuth(app);
    app.use('/api/auth', authRouter);
    app.use('/api/user', userRouter);
    app.use('/api/facility', facilityRouter);
    app.use('/api/team', teamRouter);
    app.use('/api/issues', issueRouter);
    app.use('/api/forge', forgeRouter);

    // error handlers
    // development error handler
    // will print stacktrace
    if (process.env.NODE_ENV !== 'test') {
      app.use((err: any, req: express.Request, res: express.Response, next: express.NextFunction) => {
        res.status(err.status || 500);
        res.json({
          message: err.message,
          error: err,
        });
      });
    }

    // production error handler
    // no stacktraces leaked to user
    if (process.env.NODE_ENV === 'production') {
      app.use((err: any, req: express.Request, res: express.Response, next: express.NextFunction) => {
        res.status(err.status || 500);
        res.json({
          message: err.message,
          error: {},
        });
      });
    }

    app.listen(port, () => {
      console.log(`API: Listening on port: ${port}`);
    });

然后,在 Next.js 方面:

我所做的只是收集 csrf 令牌并将它们放入我的 redux 存储中以获取 api 请求。不过有一件事:当我从 express.js web api 控制台记录 csrf 令牌以及我在 next.js 端收到的内容时,它们永远不会匹配。所以我认为这是罪魁祸首,但当当对我来说没有意义。我在某个地方犯了一个错误。

还有一个大问题,我什至需要为 SPA 方法执行此操作吗?我在 4 天内设置了一个 Django 应用程序,这非常简单,因为 html 传统上是在服务器上呈现的。

非常感谢!

【问题讨论】:

    标签: node.js reactjs security csrf next.js


    【解决方案1】:

    我想通了。

    我需要做的是获取“ res.cookie('XSRF-TOKEN', token);” cookie 在我的前端 js 应用程序中,并将其作为 _csrf 放在我的 req.body 中。现在可以了!

    【讨论】:

    • 已经一年多了,但不介意我这么说,但我不认为 CSRF 应该是这样工作的。我发布这个以防有人看到这个帖子并实施相同的解决方案。你应该让你的cookie服务器httpOnly所以它不能被javascript读取->更多阅读CSRFgithub.com/pillarjs/understanding-csrf#csrf-tokens
    • 是的,我认为你是对的。我最终使用了 httpOnly。自从这篇文章以来,学到了很多关于 CSRF 的知识。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-08-30
    • 1970-01-01
    • 2021-04-17
    • 1970-01-01
    • 1970-01-01
    • 2012-07-28
    • 2017-07-25
    相关资源
    最近更新 更多