First time adding SCRF protection by 'csurf' module. I want to put SCRF-token into cookie, pull it on client side and make a SCRF-token header that will be compared with SCRF-token from cookies on server side caused by every POST/PUT requests. My stack is: React + Redux + NodeJS + Express. But I'm always getting ForbiddenError: invalid csrf token. Its seems so minor, but I already wasted one day for fixing it. I'm definately missing smth evident(((
Server:
app.js
import { CookieOptions } from './types/server';
import express, { Request, Response, Express } from "express";
import path from 'path'
import https from 'https';
import fs from 'fs';
import csrf from 'csurf';
import helmet from 'helmet';
import cors from "cors";
import cookieSession from "cookie-session";
import passport from "passport";
import 'dotenv/config';
import logger, { morganOption } from "./config/winston";
import morgan from "morgan";
import routes from './routes/index'
import cookieParser from 'cookie-parser';
import bodyParser from 'body-parser';
const app: Express = express();
const port: string | number = process.env.PORT || 3000;
const httpsOptions = {
key: fs.readFileSync("./config/www/keys/key.pem"),
cert: fs.readFileSync("./config/www/keys/cert.pem")
};
const cookieOptions: CookieOptions = {
maxAge: 30 * 24 * 60 * 60 * 1000,
keys: [process.env.COOKIE_KEY],
resave: false,
saveUninitialized: false,
secure: true,
httpOnly: true
}
app.use(morgan("combined", morganOption));
app.use(cors());
app.use(helmet());
app.use(express.json());
app.use(cookieParser())
app.use(cookieSession(cookieOptions));
app.use(passport.initialize());
app.use(csrf({ cookie: { key: 'XSRF-TOKEN' } }));
app.use('/', routes);
const mode: string = process.env.NODE_ENV;
try {
if (mode === "production ") {
app.use(express.static("../client/build"));
app.get("*", (req: Request, res: Response) => {
res.sendFile(path.resolve(__dirname, "/index.html"));
});
}
https.createServer(httpsOptions, app).listen(port, () => {
console.log("Server works on port: " + port);
});
} catch (error) {
console.log("Error: " + error);
process.exit(1);
}
export default app
User:
input.js:
import React from "react";
import classes from "./input.module.scss";
import { Props } from "../../../types/components/input";
const Input: React.FC<Props> = (props) => {
const inputClasses = props.error
? `${classes.input} ${classes.invalid}`
: classes.input;
const spanClasses = props.error
? `${classes.input__inform} ${classes.invalid}`
: classes.input__inform;
return (
<div className={classes.wrapper}>
<input type="hidden" name="XSRF-TOKEN" value=""/>
<input
className={inputClasses}
defaultValue={props.value}
type={props.type}
autoComplete={props.autoComplete}
name={props.name}
placeholder={props.placeholder}
ref={props.register(props.rules)}
onChange={(evt) => props.onChangeHandler(evt.target.value, props.name)}
/>
<span className={spanClasses}>
{props.error ? props.error.message : props.inform}
</span>
</div>
);
};
export default Input;
Its creating a header:
Accept: application/json, text/plain, */*
Accept-Encoding: gzip, deflate, br
Accept-Language: ru-UA,ru;q=0.9,uk-UA;q=0.8,uk;q=0.7,en-US;q=0.6,en;q=0.5,ru-RU;q=0.4
Connection: keep-alive
Content-Length: 52
Content-Type: application/json;charset=UTF-8
Cookie: XSRF-TOKEN=KL6lJ5ycmqwJgAsop78o5zhN
Host: localhost:3006
Origin: https://localhost:3006
Referer: https://localhost:3006/signin
Sec-Fetch-Dest: empty
Sec-Fetch-Mode: cors
Sec-Fetch-Site: same-origin
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36
X-XSRF-TOKEN: KL6lJ5ycmqwJgAsop78o5zhN
But middleware always throws an error((
If compare it manually, I'm getting true:
app.use('/', (req, res, next) => {
console.log(req.headers.cookie.match(/(?<=XSRF-TOKEN=).+/g)[0] === req.headers['x-xsrf-token'])
next();
});
question from:
https://stackoverflow.com/questions/65938894/forbiddenerror-invalid-csrf-token-nodejs-express