以下是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错误,不知道为什么....(见下面的屏幕截图),有什么建议可以让它工作吗?
并且在后端出现错误:
如果我使用 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 选项中使用多种方式并在请求发送到后端之前编写了一些自定义头文件,但都没有成功,我得到了相同的错误消息:
我对这个问题有点困惑,CORS / CSRF 对于 spa 来说是一个大问题,我的问题仍然是相同的,在 CORS 和 SameSite cookie 属性下,由于我的 api 在 前端域名的子域中,是否真的有必要进行 anti-csrf 模式?
另外,我该如何让我的自定义头有效,并且为什么CORS告诉我没有“Access-Control-Allow-Origin”头,但事实上有呢:
app.use(cookieParser()); app.use(csurf({ cookie: true }));
- flyingpluto7