CSRF Token in Mean Stack - node.js

I am not able to integrate CSRF token of express with XSRF TOKEN of Angular. I am using the given tutorial
https://jasonwatmore.com/post/2020/09/08/nodejs-mysql-boilerplate-api-with-email-sign-up-verification-authentication-forgot-password.
I know code is in rough style but I need to solve the issue.
Here is my code of express
server.js(main)
require('rootpath')();
const express = require('express');
const app = express();
const helmet = require("helmet");
const bodyParser = require('body-parser');
var cookieParser = require('cookie-parser')
var csrf = require('csurf')
const cors = require('cors');
const errorHandler = require('_middleware/error-handler');
app.use(cookieParser());
app.use(csrf({ cookie: true }))
app.use(helmet({ dnsPrefetchControl: { allow: true }}));
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());
app.all('*', function (req, res) {
res.cookie('XSRF-TOKEN', req.csrfToken())
})
app.use(cors({ origin: (origin, callback) => callback(null, true), credentials: true }));
// api routes
app.use('/accounts', require('./accounts/accounts.controller'));
// swagger docs route
app.use('/api-docs', require('_helpers/swagger'));
// global error handler
app.use(errorHandler);
// start server
const port = process.env.NODE_ENV === 'production' ? (process.env.PORT || 80) : 4000;
app.listen(port, () => console.log('Server listening on port ' + port));
In Angular I have added in XSRF TOKEN in module.ts
imports: [
BrowserModule,
ReactiveFormsModule,
HttpClientModule,
HttpClientXsrfModule.withOptions({
cookieName: 'XSRF-TOKEN',
headerName: 'X-XSRF-TOKEN'
}),
AppRoutingModule
],
Kindly Help me to sort out the issue

I have used different which solved my problem.
here is the link
https://www.npmjs.com/package/express-csrf-double-submit-cookie
const cookieParser = require('cookie-parser')
const csrfDSC = require('express-csrf-double-submit-cookie')
const express = require('express')
// create middleware
const csrfProtection = csrfDSC();
const app = express();
app.use(cookieParser());
// middleware to set cookie token
app.use(csrfProtection)
// protect /api
app.post('/api', csrfProtection.validate, function (req, res) {
res.status(200).end();
})
previously I was using
https://www.npmjs.com/package/csurf
for my single page application

Related

Cannot get Stored Cookies from browser in Express Js

Ive set user cookie as a jwt token in the browser and it is setted up successfully but when I try to get that cookie using req.cookies it gives me undefined and [object: null prototype] {}. Heres my code
exports.isAuthenticated = asyncErrorHandler(async (req, res, next) => {
//fetching the jwt token from the cookie
const { token } = req.cookies;
console.log(req.cookies);
if (!token) return next(new ErrorHandler("plz log in first ", 400));
//verifying the given token matches the jwt stored token
const decodedData = jwt.verify(token, process.env.JWT_SECRET);
req.user = await userModel.findById(decodedData.id);
next();
});
this is my express app.js file
const express = require("express");
const errorMiddleware = require("./middleware/error");
const cookieParser = require("cookie-parser");
const bodyparser = require("body-parser");
const fileupload = require("express-fileupload");
const cors = require("cors");
const app = express();
app.use(cookieParser());
app.use(express.json());
app.use(bodyparser.urlencoded({ extended: true }));
app.use(fileupload());
app.use(
cors({
credentials: true,
origin: "http://127.0.0.1:5173",
optionsSuccessStatus: 200,
})
);
// Route Imports
const productRoutes = require("./routes/productRoutes");
const userRoutes = require("./routes/userRoutes");
const orderRoutes = require("./routes/orderRoute");
const bodyParser = require("body-parser");
app.use("/api/v1", productRoutes);
app.use("/api/v1/user", userRoutes);
app.use("/api/v1", orderRoutes);
//error HAndler Middleware
app.use(errorMiddleware);
module.exports = app;
Ive tried cookie-parseer and also had cors in my express app file. ive set the cookie key as token
the req.cookies isn't the right way to get cookies
If you want to get cookies it is in the header so you must get cookies from header from the request like this :
console.log(req.headers.cookie)

Is There A Way To Fix This Cors Error On Heroku

I have a full stack app but when I uploaded my backend to heroku, on browsers cors policy is blocking my API routes. I get the error
No ‘Access-Control-Allow-Origin’ header is present on the requested resource.)
on heroku I get a 503 error for the routes. I am requesting https from an https origin on netlify which is my frontend. I tried to fix it but it does not solve all my cors errors.
index.js
const express = require("express");
const app = express();
const PORT = process.env.PORT || 8500
const mongoose = require("mongoose");
const dotenv = require("dotenv");
const helmet = require("helmet");
const morgan = require("morgan");
const bodyParser = require("body-parser");
const cookieParser = require("cookie-parser");
const errorHandler = require("./middleware/error");
const cors = require("cors");
// setting cors
const corsOptions = {
origin: ['*', '*'],
preflightContinue:false,
credentials: true,
methods: 'GET,HEAD,PUT,PATCH,POST,DELETE',
}
//Import Routes
const Routes = require('./routes/routes');
dotenv.config();
//middleware
app.use(cors(corsOptions));
app.use(express.json());
app.use(helmet());
app.use(bodyParser.json());
app.use(morgan("dev"));
app.use(cookieParser());
app.use("/api", Routes);
//welcome message
app.get('/', (req,res) => {
console.log("Welcome to the API.")
});
app.get('/greeting', (req,res) => {
res.json({greeting: 'Hello there'})
});
mongoose.connect(process.env.MONGO_URL, {useNewUrlParser: true, useUnifiedTopology: true}).then(() => {
console.log("MongoDB Connected")
})
.catch((err) => console.log(err));
app.listen(PORT, ()=> {
console.log("Backend server is running!")
})

"Indicate whether to send a cookie in a cross-site request by specifying its SameSite attribute"

Hey I am working on a stripe project which redirect the user to stripe portal for payment but got stuck when I got this error :
Indicate whether to send a cookie in a cross-site request by specifying its SameSite attribute?
Here is my server.js in which I also has set the header :
const express = require('express')
const morgan = require('morgan')
const connectDB = require('./config/db')
const bodyParser = require('body-parser')
const cors = require('cors')
const jwt = require('jsonwebtoken')
const uuid = require("uuid")
// Config dotev
require('dotenv').config({
path: './config/config.env'
})
const stripe = require("stripe")(process.env.STRIPE_SECRET_KEY)
const app = express()
// Connect to database
connectDB();
// body parser
app.use(bodyParser.json())
app.use(bodyParser.urlencoded({ extended: true }))
//header
app.use((req,res) => {
res.cookie('cookie', 'value', { sameSite: 'none', secure: true })
})
// Load routes
const authRouter = require('./routes/auth.route')
const stripeRouter = require('./routes/stripe.route')
// Dev Logginf Middleware
if (process.env.NODE_ENV === 'development') {
app.use(cors({
origin: process.env.CLIENT_URL
}))
app.use(morgan('dev'))
}
// Use Routes
app.use('/api', authRouter)
app.use('/api' , stripeRouter)
app.use((req, res) => {
res.status(404).json({
success: false,
msg: "Page not founded"
})
})
const PORT = process.env.PORT || 5000
app.listen(PORT, () => {
console.log(`App listening on port ${PORT}`);
});

Why is node.js not passing my session to a segment it calls

In node.js, my entrypoint segment (app.js) calls another segment after the express session has been set up. The segment called is expecting a session field in the request ('req') object but it isn't there.
This is app.js in full:
const express = require('express');
const path = require('path');
const nunjucks = require('nunjucks');
const helmet = require('helmet');
const csp = require('helmet-csp');
const uuid = require('uuid/v4');
const fs = require('fs');
const https = require('https');
const cookieMiddleware = require('./app/middleware/cookie-message.js');
const cookieDetailsGet = require('./app/routes/cookies/cookie-details.get.js');
const cookiePolicyPost = require('./app/routes/cookies/cookie-policy.post.js');
const cookiePolicyGet = require('./app/routes/cookies/cookie-policy.get.js');
const nonceMiddleware = require('./app/middleware/nonce.js');
const cookieParser = require('cookie-parser');
let app = express();
const session = require('express-session');
const RedisStore = require('connect-redis')(session);
const bodyParser = require('body-parser');
const i18next = require('i18next');
const i18nextMiddleware = require('i18next-express-middleware');
const i18nextFsBackend = require('i18next-node-fs-backend');
const config = require('./app/config/config');
const i18nextOptions = require('./app/config/i18nextOptions');
const { getRedisClient } = require('./app/services/redis-client');
const router = express.Router;
/* Generate nonce. */
const nonce = Buffer.from(uuid().toString('base64'));
app.use((req, res, next) => {
res.locals.nonce = nonce;
next();
});
// configure Nunjucks templating
nunjucks.configure(['views',
path.join(__dirname, 'node_modules/morris-frontend/'),
path.join(__dirname, 'node_modules/morris-frontend/morris/components/'),
path.join(__dirname, 'app/views/')
], {
autoescape: true,
express: app
});
// secure apps by setting various HTTP headers
app.use(helmet());
app.use(csp({
directives: {
defaultSrc: ["'self'"],
styleSrc: ["'self'"],
scriptSrc: [
"'self'",
`'nonce-${nonce}'`, // Pass the nonce value along.
"'sha256-+6WnXIl4mbFTCARd8N3COQmT3bJJmo32N8q8ZSQAIcU='",
],
imgSrc: ["'self'"],
fontSrc: ["'self'"]
}
}));
// referrerPolicy
app.use(helmet.referrerPolicy({ policy: 'no-referrer-when-downgrade' }));
// view engine setup
app.set('views', path.join(__dirname, 'app/views'));
app.set('view engine', 'html');
app.use(bodyParser.urlencoded({
extended: true
}));
app.use(cookieParser());
cookieMiddleware(
app,
config.CONSENT_COOKIE_NAME,
config.COOKIE_POLICY,
config.COOKIE_CONSENT,
'/decision/',
config.GOOGLE_TAG_MANAGER_DOMAIN
);
// Language support
i18next.use(i18nextFsBackend)
.use(i18nextMiddleware.LanguageDetector)
.init(i18nextOptions);
app.use(i18nextMiddleware.handle(i18next, {
removeLngFromUrl: false
}));
// Redis session
const sessionStore = new RedisStore({
client: getRedisClient(),
prefix: 'bl:',
ttl: parseInt(config.sessionTTL, 10),
logErrors: (err) => {
log.error('Redis session error', {
err_message: err.message,
err_stack: err.stack
});
}
});
app.use(session({
secret: config.sessionSecret,
store: sessionStore,
resave: false,
saveUninitialized: false
}));
app.use(bodyParser.json());
app.use('/decision', express.static(path.join(__dirname, 'node_modules/morris-frontend/morris')));
app.use('/decision', express.static(path.join(__dirname, 'app/public/grants')));
// Cookie policy pages
app.get(`/${config.COOKIE_DETAILS}`, cookieDetailsGet(
config.COOKIE_POLICY,
config.CONSENT_COOKIE_NAME,
config.SESSION_COOKIE_NAME,
config.COOKIE_CONSENT,
config.sessionsTTL
));
app.get(`/${config.COOKIE_POLICY}`, cookiePolicyGet(config.COOKIE_DETAILS));
app.post(`/${config.COOKIE_POLICY}`, cookiePolicyPost(
config.CONSENT_COOKIE_NAME,
'/',
config.GOOGLE_TAG_MANAGER_DOMAIN
));
// Defining the Router
//app.use(require('./app/routes/routes'));
require('./app/routes/monitoring')(app);
if (process.env.HTTPS_ON === 'true') {
const httpsKeys = {
key: fs.readFileSync(process.env.HTTPS_KEY, 'utf-8'),
cert: fs.readFileSync(process.env.HTTPS_CRT, 'utf-8')
};
app = https.createServer(httpsKeys, app);
}
app.listen(process.env.PORT || 3001, () => {
const protocol = process.env.HTTPS_ON ? 'https' : 'http';
const port = process.env.PORT || 3001;
console.log(`Server running on ${protocol}://localhost:${port}`); // eslint-disable-line no-console
});
module.exports = { app, router };
The call that's messing up is this bit:
cookieMiddleware(
app,
config.CONSENT_COOKIE_NAME,
config.COOKIE_POLICY,
config.COOKIE_CONSENT,
'/decision/',
config.GOOGLE_TAG_MANAGER_DOMAIN
);
Here's the top part of cookie-message.js (the segment being called:
const qs = require('querystring');
const setConsentCookie = require('../utils/set-consent-cookie.js');
const removeGTMCookies = require('../utils/remove-gtm-cookies.js');
module.exports = (app, consentCookieName, cookiePolicy, cookieConsent, mountUrl, proxyMountUrl = mountUrl, gtmDomain, useTLS = false) => {
const reProxyMountUrl = new RegExp(`^${proxyMountUrl}`);
const sanitiseUrl = (url) => url.replace(reProxyMountUrl, mountUrl).replace(/\/+/g, '/');
// URL to cookie policy page
const cookiePolicyUrl = `${mountUrl}${cookiePolicy}`;
// Set template options for cookie consent banner
app.use((req, res, next) => {
console.log('inside cookie-message.js');
console.log('req.session=', req.session);
The console.log call shows req.session as being undefined.
Any suggestions?
If you want to use the session inside of the cookieMiddleware(), then you have to move the session middleware to be BEFORE cookieMiddleware() is called. Right now, you have the session middleware after so req.session has not yet been configured when cookieMiddleware() gets called.
Middleware is run in the order it is registered so to use req.session, the session middleware has to have already run before the middleware where you're trying to use req.session. So, you can either move cookieMiddleware() to be later (after session middleware) or move your session middleware earlier before cookieMiddleware() is called.

CSRF protection for Node.js Express 4 and passport.js not working

Using csurf, I am trying to integrate csrf protection into my node.js express 4 application. This is my code:
EDIT: The code below was updated according to the solution I found.
"use strict";
var http = require('http');
var https = require('https');
var port = process.env.PORT || 80,
express = require('express'),
csrf = require('csurf'),
bodyParser = require('body-parser');
var LocalStrategy = require('passport-local').Strategy,
csrfProtection = csrf({ cookie: true }),
mongoose = require('mongoose'),
conn = mongoose.createConnection('foo'),
cookieParser = require('cookie-parser'),
passport = require('passport'),
session = require('express-session'),
MongoStore = require('connect-mongo')(session),
app = express();
app.set('view engine', 'ejs');
var csrfProtection = csrf({ cookie: true }); // doesn't work either
require('passport')(passport);
app.use(cookieParser("foo"));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended: true})); //extended: true|false does not make any difference
app.use(session({
//foo
}));
app.use(passport.initialize());
app.use(passport.session());
require('./app/routes.js')(app, passport); //routes inside here cause a ReferenceError: csrfProtection is not defined
http.createServer(app).listen(port);
https.createServer(options, app).listen(443, function () {
//foo
});
-- routes.js --
var csrf = require('csurf'), //this needs to go in here
csrfProtection = csrf(); //this needs to go in here
module.exports = function(app, passport) {
app.route('/somepage')
.get(csrfProtection, function(req, res) {
res.render('somepage', { csrfToken: req.csrfToken()});
});
};
-- routes.js end--
For some strange reason csrfProtection remains unknown inside my page routes causing a ReferenceError (see comment inside code). What am I missing?
EDIT:
ignoreMethods
An array of the methods for which CSRF token checking will disabled. Defaults to ['GET', 'HEAD', 'OPTIONS'].
Try and set it to ['HEAD','OPTIONS']
csrfProtection = csrf(
{ cookie: true, ignoreMethods:['HEAD','OPTIONS' ] }
)

Resources