为什么我收到 ForbiddenError: invalid csrf token

时间:2021-06-17 12:21:40

标签: javascript html node.js express cookies

我对CSRF的token、cookies、token的理解,总体来说是很薄弱的。我一直无法让它们在我的应用程序中有效地工作。

目前,我有一个使用 express 进行路由的节点服务器。我的问题是,每当我尝试将 csurf(一个节点 csrf 中间件包)与任何应用程序集成时,它都出于某种原因不起作用。

我按照教程和所有内容尝试了很多不同的设置。

const cookieParser = require("cookie-parser");
const csrf = require("csurf");
const bodyParser = require("body-parser");
const express = require("express");
const admin = require("firebase-admin");

const serviceAccount = require("./secretKey.json");

admin.initializeApp({
  credential: admin.credential.cert(serviceAccount),
});

const csrfMiddleware = csrf({ cookie: true });

const PORT = process.env.PORT || 3000;
const app = express();

app.engine("html", require("ejs").renderFile);
app.use(express.static("static"));

app.use(bodyParser.json());
app.use(cookieParser());
app.use(csrfMiddleware);

app.all("*", (req, res, next) => {
  console.log(req)
  res.cookie("XSRF-TOKEN", req.csrfToken());
  next();
});

app.get("/login", function (req, res) {
  res.render("login.html");
});

app.get("/signup", function (req, res) {
  res.render("signup.html");
});

app.get("/profile", function (req, res) {
  const sessionCookie = req.cookies.session || "";

  admin
    .auth()
    .verifySessionCookie(sessionCookie, true /** checkRevoked */)
    .then(() => {
      res.render("profile.html");
    })
    .catch((error) => {
      res.redirect("/login");
    });
});

app.get("/", function (req, res) {
  res.render("index.html");
});

app.post("/sessionLogin", (req, res) => {
  const idToken = req.body.idToken.toString();

  const expiresIn = 60 * 60 * 24 * 5 * 1000;

  admin
    .auth()
    .createSessionCookie(idToken, { expiresIn })
    .then(
      (sessionCookie) => {
        const options = { maxAge: expiresIn, httpOnly: true };
        res.cookie("session", sessionCookie, options);
        res.end(JSON.stringify({ status: "success" }));
      },
      (error) => {
        res.status(401).send("UNAUTHORIZED REQUEST!");
      }
    );
});

app.get("/sessionLogout", (req, res) => {
  res.clearCookie("session");
  res.redirect("/login");
});

app.listen(PORT, () => {
  console.log(`Listening on http://localhost:${PORT}`);
});

上面的代码片段实际上直接取自这个 youtube 教程,并做了一些小调整: https://www.youtube.com/watch?v=kX8by4eCyG4&ab_channel=MaksimIvanov (firebase 用于身份验证,但这无关)

我的问题是,每次我尝试通过“登录”路由登录时,我都会在节点控制台中收到此错误。

ForbiddenError: invalid csrf token

这是登录页面的正文

        <main>
            <section>
                <form id="login">
                    <label>Login</label>
                    <input type="text" name="login" />
                    <label>Password</label>
                    <input type="password" name="password" />
                    <button>Log in</button>
                </form>
            </section>

            <script>
                window.addEventListener("DOMContentLoaded", () => {
                    var firebaseConfig = { some private stuff };
                    firebase.initializeApp(firebaseConfig);

                    firebase
                        .auth()
                        .setPersistence(firebase.auth.Auth.Persistence.NONE);

                    document
                        .getElementById("login")
                        .addEventListener("submit", (event) => {
                            event.preventDefault();
                            const login = event.target.login.value;
                            const password = event.target.password.value;

                            firebase
                                .auth()
                                .signInWithEmailAndPassword(login, password)
                                .then(({ user }) => {
                                    return user.getIdToken().then((idToken) => {
                                        return fetch("/sessionLogin", {
                                            method: "POST",
                                            headers: {
                                                Accept: "application/json",
                                                "Content-Type":
                                                    "application/json",
                                            },
                                            body: JSON.stringify({ idToken }),
                                        });
                                    });
                                })
                                .then(() => {
                                    return firebase.auth().signOut();
                                })
                                .then(() => {
                                    window.location.assign("/profile");
                                });
                            return false;
                        });
                });
            </script>

目前,我的实际项目有不同的设置,但即使是本教程设置似乎也不起作用。我仍然收到错误:ForbiddenError: invalid csrf token

我想知道为什么会遇到此问题,但 youtube 教程却没有。我还想知道是否可以将 csrf 令牌发送到独立的前端(与后端完全分开),因为这是我实际想要的设置。当前示例中的设置从服务器本身提供静态 HTML。

我正在本地主机上手动测试和开发所有内容。

0 个答案:

没有答案