NestJS 中的 CSRF 令牌无效。

5
我希望使用NestJS和Quasar实现Csrf保护,但我认为我对此有一些误解......顺便说一下,我没有做SSR,所以我不会从后端向视图发送表单。
以下是NestJs后端代码:
    async function bootstrap() {
  const PORT = process.env.PORT;
  const app = await NestFactory.create(AppModule, {
    cors: true,
    bodyParser: false,
  });
  console.log(`your App is listening on port ${PORT}`);

  // Added Cookie-parser to user csurf packages
  // Prevent CSRF attack
  app.use(cookieParser());
  app.use(csurf({ cookie: true }));

  await app.listen(PORT);
}
bootstrap();

所以我只是在使用 CookieParser 和 csurf 包。 在我的登录页面上,我调用了一个“csrf endpoint”来发送一个 cookie 到视图,然后将其与 post 调用(登录)一起发送回来。 我仍然收到“invalid csrf token”和CORS错误,不知道为什么....(见下面的屏幕截图),有什么建议可以让它工作吗?

csrf cookie

当我尝试登录时,浏览器中出现错误: CORS error

Error 500 login

并且在后端出现错误:

nestjs csrf errror

如果我使用 Insomnia 发送请求,会出现同样的错误。 我认为 CSRF 令牌附加到“Web 浏览器”,以便通过 nest 请求返回到后端,那么为什么我仍然会收到此错误? Insomnia 自动发送正确请求与 cookie,所以令牌应该返回到后端。 有任何想法吗? 谢谢

编辑: 经过多次阅读文档,似乎 CSRF 保护只用于 SSR?在 SPA 中不需要添加 CSRF 安全性?有人能确认吗?

编辑:这里还有另一份作品:

这里的目的是在登录之前发送一个请求来获取一个 csrf 令牌,然后将其放入一个 cookie 中,在使用 POST 方法进行登录时重新发送。

这是我的端点:

import { Controller, Get, Req, Res, HttpCode, Query } from "@nestjs/common";

@Controller("csrf")
export class SecurityController {
  @Get("")
  @HttpCode(200)
  async getNewToken(@Req() req, @Res() res) {
    const csrfToken = req.csrfToken();

    res.send({ csrfToken });
  }
}

这是我在 main.ts 文件中所做的(下面我会解释):
async function bootstrap() {
  const PORT = process.env.PORT;
  const app = await NestFactory.create(AppModule, {
    cors: {
      origin: "*",
      methods: ["GET,HEAD,OPTIONS,POST,PUT"],
      allowedHeaders: [
        "Content-Type",
        "X-CSRF-TOKEN",
        "access-control-allow-methods",
        "Access-Control-Allow-Origin",
        "access-control-allow-credentials",
        "access-control-allow-headers",
      ],
      credentials: true,
    },
    bodyParser: false,
  });
  app.use(cookieParser());
  app.use(csurf({ cookie: true }));
  console.log(`your App is listening on port ${PORT}`);

  await app.listen(PORT);
}
bootstrap();

以下是我在VueJS前端中使用的axiosInstance请求拦截器:

axiosInstance.interceptors.request.use(
(req) => {
  const token = Cookies.get('my_cookie')
  if (token) {
    req.headers.common['Authorization'] = 'Bearer ' + token.access_token
  }

  req.headers['Access-Control-Allow-Origin'] = '*'
  req.headers['Access-Control-Allow-Credentials'] = 'true'
  req.headers['Access-Control-Allow-Methods'] = 'GET,HEAD,OPTIONS,POST,PUT'
  req.headers['Access-Control-Allow-Headers'] =
    'access-control-allow-credentials,access-control-allow-headers,access-control-allow-methods,access-control-allow-origin,content-type,x-csrf-token'

  const csrfToken = Cookies.get('X-CSRF-TOKEN')
  if (csrfToken) {
    req.headers['X-CSRF-TOKEN'] = csrfToken
    console.log(req)
  }

  return req
},
(err) => {
  console.log(err)
},

这里同样适用于响应(response):

axiosInstance.interceptors.response.use(
(response) => {
  if (response?.data?.csrfToken) {
    const {
      data: { csrfToken },
    } = response
    Cookies.set('X-CSRF-TOKEN', csrfToken)
  }

  return response
},

在我的登录页面内,我调用了登录组件中的 mounted 函数:

 async mounted() {
const result = await securityService.getCsrf()

现在来解释一下:

就像我之前所说,我不是在构建 SSR 项目,因此我想将令牌发送到经典的 axios 响应中,并将其存储在 Cookie 中(这部分是为测试而听到的,将 csrf 令牌存储在经典Cookie 中并不是正确的方法)。对于每个后续请求,我获取 csrf 令牌并将其“附加”到头文件中的请求中,使我的头文件变成“自定义”的。这里有一个问题,我不知道如何让 nestJS 和 CORS 使用自定义头文件,这就是为什么我尝试在 NestJS 的 CORS 选项中使用多种方式并在请求发送到后端之前编写了一些自定义头文件,但都没有成功,我得到了相同的错误消息:

another CORS problem

我对这个问题有点困惑,CORS / CSRF 对于 spa 来说是一个大问题,我的问题仍然是相同的,在 CORS 和 SameSite cookie 属性下,由于我的 api 在 前端域名的子域中,是否真的有必要进行 anti-csrf 模式?

另外,我该如何让我的自定义头有效,并且为什么CORS告诉我没有“Access-Control-Allow-Origin”头,但事实上有呢:

Request headers


嗯,我还在尝试不同的方法,我会编辑主要信息,加入昨天的工作。 - De_Jr
在我的端上运行良好。 app.use(cookieParser()); app.use(csurf({ cookie: true })); - flyingpluto7
会再试一次,我会在这里发布最终的解决方案!谢谢! - De_Jr
1个回答

0
尝试生成 CSRF 令牌并在每个请求中传递到前端。
// main.ts - from NestJs - Backend
// after app.use(csurf({ cookie: true }))

app.use((req: any, res: any, next: any) => {
  const token = req.csrfToken()
  res.cookie("XSRF-TOKEN", token)
  res.locals.csrfToken = token
  next()
})

来自:https://github.com/nestjs/nest/issues/6552#issuecomment-1175270849


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接