-
Notifications
You must be signed in to change notification settings - Fork 22
Open
Description
I have made doubleCSRFprotection middleware and a middleware that sends the CSRF token in every page.
realestate\middleware\csrfToken.ts:
const {
generateCsrfToken, // Use this in your routes to provide a CSRF token.
doubleCsrfProtection // This is the default CSRF protection middleware.
} = doubleCsrf({
getSecret: () => process.env.CSRF_SECRET!,
getSessionIdentifier: (req: any) => req.session.id
});
function csrfToken(req: Request, res: Response, next: any) {
res.locals.csrfToken = generateCsrfToken(req, res);
next();
}
export { doubleCsrfProtection, csrfToken };I have put the doubleCsrfProtection in app.ts and also csrfToken to have the CSRF token be accessed globally, especially in the global header.
realestate\app.ts:
const app = express();
const __dirname = import.meta.dirname;
app.use(
session({
secret: process.env.SESSION_SECRET!,
resave: true,
saveUninitialized: true
})
);
app.use(cookieParser(process.env.COOKIE_SECRET!));
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
app.use(express.static(join(__dirname, "public")));
app.disable("x-powered-by");
// view engine setup
app.set("view engine", "ejs").set("views", join(__dirname, "views"));
// 4 CSRF tokens
app.use(doubleCsrfProtection);
app.use(csrfToken);realestate\views\partials\header.ejs:
<body class="d-flex flex-column">
<!-- Navbar -->
<nav class="navbar navbar-expand-md bg-secondary sticky-top py-0 mx-0 mb-3">
<div class="container-fluid">
<!-- ... -->
<div class="collapse navbar-collapse" id="toggler">
<!-- ... -->
<ul class="navbar-nav">
<!-- 1 Authentication & authorization -->
<% if (auth) { %>
<li class="nav-item btn btn-secondary px-md-1 py-md-3">
<a class="nav-link fw-semibold text-light" href="/korisnici/<%= auth.id %>">Profil</a>
</li>
<li class="nav-item btn btn-secondary px-md-1 py-md-3">
<form action="/odjava" method="post">
<!-- 4 CSRF tokens -->
<input type="hidden" name="_csrf" value="<%= csrfToken %>">
<input class="nav-link fw-semibold text-light" type="submit" value="Odjava">
</form>
</li>
<% } else { %>
<li class="nav-item btn btn-secondary px-md-1 py-md-3">
<a class="nav-link fw-semibold text-light" href="/registracija">Registracija</a>
</li>
<li class="nav-item btn btn-secondary px-md-1 py-md-3">
<a class="nav-link fw-semibold text-light" href="/prijava">Prijava</a>
</li>
<% } %>
</ul>
</div>
</div>
</nav>Other templates where I use CSRF token:
realestate\views\listings\listing_create.ejs:
<%- include("../partials/header", { title: "Postavka novog oglasa" }) %>
<h1 class="fw-bold mb-3">Postavka novog oglasa</h1>
<div class="row">
<div class="col-md-6 col-lg-8">
<form class="border border-secondary-subtle rounded-3 p-3 mb-3" action="/oglasi/postavka" method="post" novalidate>
<!-- 4 CSRF tokens -->
<input type="hidden" name="_csrf" value="<%= csrfToken %>">
<!-- ... -->
<input class="btn btn-primary fw-semibold" type="submit" value="Postavi">
</form>
</div>
</div>
<%- include("../partials/footer") %>realestate\views\auth\login.ejs:
<%- include("../partials/header", { title: "Prijava" }) %>
<h1 class="fw-bold mb-3">Prijava</h1>
<div class="row">
<div class="col-md-6 col-lg-4">
<form class="border border-secondary-subtle rounded-3 p-3 mb-3" action="/prijava" method="post" novalidate>
<p class="mb-3">Nemaš nalog? <a href="/registracija">Registruj se</a></p>
<!-- 4 CSRF tokens -->
<input type="hidden" name="_csrf" value="<%= csrfToken %>" />
<!-- ... -->
<input class="btn btn-primary fw-semibold" type="submit" value="Prijavi se" />
</form>
</div>
</div>
<%- include("../partials/footer") %>realestate\views\partials\listings\list\footer.ejs (I also use CSRF tokens in partials):
<!-- Card footer -->
<div class="card-footer d-flex justify-content-between align-items-center">
<span class="fw-lighter">
<% if (listing.isUpdated()) { %>
Ažuriran: <%= moment(listing.updatedAt).format("DD.MM.YYYY HH:MM") %>
<% } else { %>
Postavljen: <%= moment(listing.createdAt).format("DD.MM.YYYY HH:MM") %>
<% } %>
</span>
<form action="/oglasi/cuvanje/<%= listing.id %>" method="post">
<!-- 4 CSRF tokens -->
<input type="hidden" name="_csrf" value="<%= csrfToken %>">
<button class="btn btn-link" type="submit">
<% if (listing.isSaved(authId)) { %>
<i class="bi bi-bookmark-fill text-success fs-4"></i>
<% } else { %>
<i class="bi bi-bookmark text-success fs-4"></i>
<% } %>
</button>
</form>
</div>For example, when I press submit button in Login form, the CSRF token is invalid.
ForbiddenError: invalid csrf token
at doubleCsrf (file:///D:/Documents/_Dokumenti/Projekti/_Master/Real%20Estate%20Listings%20App/Secure/Node/realestate/node_modules/csrf-csrf/dist/index.js:30:33)
at <anonymous> (D:\Documents\_Dokumenti\Projekti\_Master\Real Estate Listings App\Secure\Node\realestate\middleware\csrfToken.ts:8:5)
at ModuleJob.run (node:internal/modules/esm/module_job:413:25)
at process.processTicksAndRejections (node:internal/process/task_queues:103:5)
at async onImport.tracePromise.__proto__ (node:internal/modules/esm/loader:660:26)
at async asyncRunEntryPointWithESMLoader (node:internal/modules/run_main:101:5)
Project repo: https://github.com/IArnaut2/Express-Realestate-CSRF-Issue.
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
No labels