如何从 CSRF 中间件中排除端点

How to exclude an endpoint from CSRF middleware

请参阅下面的更新...

我的 React 前端能够调用我的 Node 后端 API。但是,当外部站点调用我的 API 时,它会收到错误消息。如果我注释掉设置的 CSRF 部分(5 行),那么第 3 方服务就可以调用我的 API.

const express = require("express");
const cookieParser = require("cookie-parser");
const csurf = require("csurf");
var cors = require("cors");

var corsOptions = {
    origin: process.env.CORS_ORIGIN_URL.split(","),
    credentials: true,
    exposedHeaders: ["set-cookie"],
};
app.use(cors(corsOptions));

app.use(
    cookieParser(process.env.COOKIE_SECRET, {
        sameSite: true,
        httpOnly: true,
        secure: process.env.NODE_ENV === "production",
        maxAge: process.env.COOKIE_MAX_AGE,
    })
);

// If I comment out the next 5 lines, 3rd party services CAN call upon my API
app.use(csurf({ cookie: true }));
app.use(function (req, res, next) {
    res.cookie("XSRF-TOKEN", req.csrfToken());
    next();
});

app.use("/api/csrf", (req, res) => {
    return res.status(200).json({
        status: true,
        csrfToken: req.csrfToken(),
    });
});

app.use("/api", api);

更新

我想根据请求的路由(见下文)将 CSRF 配置包装在 if-else 语句中。这似乎可行,但这是正确且安全的设置吗?

var csrf = csurf({ cookie: true });

app.use(function (req, res, next) {
    // skip csrf for certain routes
    if (req.url === '/api/mollie_webhook') {
        return next();
    } else {
        app.use(csrf);
        // Is this allowed? Since we already have app.use 4 lines up, but don't know how else to do this...

        app.use(function (req, res, next) {
            res.cookie("XSRF-TOKEN", req.csrfToken());
            next();
        });

        app.use("/api/csrf", (req, res) => {
            return res.status(200).json({
                status: true,
                csrfToken: req.csrfToken(),
            });
        });

        next();
    }
});

app.use("/api", api);

这不是 CSRF 保护的目的。 CSRF 保护是为了防止直接 posting 数据到您的站点。换句话说,客户端实际上必须 post 通过批准的路径,例如将数据填写到表单并提交。

因此 api 将排除 Csrf,因为其目的通常是允许第 3 方实体访问和修改您网站上的数据。因此,作为一项规则,任何 API 视图都不应该使用 CSRF。您可以通过各种方式保护您的端点,例如 oauth,还有其他最佳实践

实现您想要的效果的最简单方法是在添加 CSRF 中间件之前声明 Web Hook 路由。

但是,您可以有条件地应用 CSRF 保护,方法是直接跳到特定忽略路由上的 next 中间件。

您还需要在 webhook 路由上启用 CORS 以允许来自远程服务器的传入请求。

const express = require('express');
const cors = require('cors');
const csurf = require('csurf');
const cookies = require('cookie-parser');
const app = express();

const shared = cors({
  origin: 'https://api.mollie.com',
  methods: 'POST'
});

const protect = csurf({ cookie: true });
const ignore = [ '/api/webhook' ];

app.use(cookies(process.env.COOKIE_SECRET, {
  sameSite: true, httpOnly: true,
  secure: process.env.NODE_ENV === "production",
  maxAge: process.env.COOKIE_MAX_AGE,
}));

app.use((req, res, next) => {
  if (ignore.includes(req.url)) {
    next();
  } else {
    protect(req, res, next);
  }
});

app.use((req, res, next) => {
  if (req.csrfToken) {
    res.cookie("XSRF-TOKEN", req.csrfToken());
  } next();
});

app.use('/api/webhook', shared, (req, res) => {
  res.sendStatus(200);
});

app.use("/api/csrf", (req, res) => {
  res.json({
    status: true,
    csrfToken: req.csrfToken(),
  });
});

app.listen(process.env.PORT);