NestJS 的 csrf 令牌无效

De_*_*_Jr 5 security vue.js axios nestjs csrf-token

我想用 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();
Run Code Online (Sandbox Code Playgroud)

所以我只使用 CookieParser 和 csurf 包。在我的登录页面上,我调用“csrf 端点”只是为了将 cookie 发送到视图,并通过 post 调用(登录)将其发送回来。我仍然收到“无效的 csrf 令牌”和 CORS 错误,但不知道为什么......(请参见下面的屏幕),有什么建议可以让它发挥作用吗?

CSRF cookie

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

登录时出现500错误

并且后台报错:

Nestjs csrf错误

如果我尝试失眠的请求,也会出现同样的错误。我认为 CSRF 令牌附加到“网络浏览器”以通过嵌套请求返回后端,那么为什么我仍然收到此错误?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 });
  }
}
Run Code Online (Sandbox Code Playgroud)

这是我在 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();
Run Code Online (Sandbox Code Playgroud)

这是我的 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)
},
Run Code Online (Sandbox Code Playgroud)

这里的回复也是一样的:

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

  return response
},
Run Code Online (Sandbox Code Playgroud)

在我的登录中,我调用登录组件的已安装函数:

 async mounted() {
const result = await securityService.getCsrf()
Run Code Online (Sandbox Code Playgroud)

},

那么现在来解释一下:

正如我所说,我不是在构建 SSR 项目,这就是为什么我想将令牌发送到经典 axios 响应并将其存储在 Cookie 中(这部分是为了测试我听说将 csrf 令牌存储到经典 cookie 中是不可行的) )对于每个下一个请求,我都会获取 csrf 令牌并将其“附加”到请求的标头中,使我的标头成为“自定义”。这是一个问题,我不知道如何使自定义标头与 NestJS 和 CORS 一起使用,这就是为什么我在 NestJS 中尝试使用 CORS 选项进行很多操作,并在请求转到后端之前编写一些自定义标头,但没有成功,我收到相同的错误消息:

另一个 CORS 问题

我对这个问题有点困惑,CORS/CSRF 对于 spa 来说是一件大事,我的问题仍然是一样的,具有 CORS 和 SameSite cookie 属性,并且我的 api 位于我前端的子域中,这真的有必要吗制作反csrf模式?

顺便说一句,我怎样才能使我的自定义标头正常工作以及为什么 CORS 对我说没有“Access-Control-Allow-Origin”标头,但有:

请求标头

小智 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()
})
Run Code Online (Sandbox Code Playgroud)

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