How to secure my react app api with csurf? - node.js

I am trying to add csrf protection to my react app but I am getting an error Invalid token all the time
import bodyParser from 'body-parser';
import cookieSession from 'cookie-session';
import passport from 'passport';
import csrf from 'csurf'
import config from '../../config'
import AuthRoutes from "./routes/AuthRoutes";
/* Test only */
import cookieParser from 'cookie-parser';
const session = cookieSession({
maxAge:24 * 60 * 60 * 1000,
keys:[config.COOKIE_KEY],
name:'authentication',
});
export default app => {
app.use(bodyParser.urlencoded({
extended: true
}));
app.use(bodyParser.json());
app.use(session);
app.use(passport.initialize());
app.use(passport.session());
/* Test */
app.use(cookieParser());
app.use(csrf({ cookie: true }));
app.use(function (err, req, res, next) {
if (err.code !== 'EBADCSRFTOKEN') return next(err)
// handle CSRF token errors here
res.status(403)
res.send('form tampered with')
})
/*Passport Config*/
require('../../services');
/* Register, Login these are routes i want to protect */
AuthRoutes(app);
}

You need to:
1. Configure csrf library on the server. This ensures the library will send the first piece of data attached to the server responses.
2. Use csrf library on the server to generate the second piece of data and attach it to the server response (e.g. HTML form sent to the client). After this step is completed the server response will carry two pieces of CSRF data.
3. On the client take the second piece of data and insert it into the request you are about to send (e.g. the form you are about to submit).
Step 1
So far only the step (1) has been completed. You asked the csrf library to send the first piece of data as a cookie. You could have used a better configuration:
app.use(csrf({cookie: {
httpOnly: true,
}}));
It ensures the browser won't allow any JS on the client to touch the first piece of data inside the cookie which is good because there is no legit reason for any script to know what is inside this cookie. Later on, in production and when you use HTTPS, you can optionally add secure: true to the above configuration to make the server refuse to send this cookie over connections that are not secure.
Step 2
To get the second piece of data call csrfToken(). The csrf middleware added another property to Request object for your convenience so it can be called like this: const secondPiece = req.csrfToken(). You can put the second piece of data into the server responce in any way or manner you like: into another cookie with an arbitrary name (except for the _csrf name already taken by the step 1 cookie) or into HTTP header named as you like.
For example this code will put it into another cookie:
res.cookie('XSRF-TOKEN', req.csrfToken());
Step 3
On the client write JS to get the second piece of data and put it into one of the predefined places/locations (inside the request to be sent to the server) where csrf middleware searches for it by default.

Just in case, any solutions doesn't work.
I just had days of debugging caused by incorrect naming of the cookie. Make sure to name your cookie XSRF-COOKIE(take note it uses - symbol) because I incorrectly named mine using underscore XSRF_COOKIE and this bit my ass for days.

Related

socket.request and socket.request.res

I am trying to use session middleware to the socket io server, but cannot understand what the (socket.request) and (socket.request.res) are.
var sessionMiddleWare = session({
secret: 'fastcampus',
resave: false,
saveUninitialized: true,
cookie: {
maxAge: 2000 * 60 * 60
},
store: new SequelizeStore({
db: db.sequelize
}),
});
app.use(sessionMiddleWare);
...
var server = app.listen(port, function(){
console.log('Express listening on port', port);
});
var listen = require('socket.io');
var io = listen(server);
io.use(function(socket, next){
sessionMiddleWare(socket.request, socket.request.res, next);
});
require('./libs/socketConnection')(io);
I`m confusing with the
io.use(function(socket, next){
sessionMiddleWare(socket.request, socket.request.res, next);
});
because when I use the sessionMiddelWare in the local app,
just using
app.use(sessionMiddleWare)
Need some help.. thanks
Here's a breakdown of what's happening in the code that got you puzzled:
You have cookie session middleware running in your express app, just doing what it usually does (adding session data to each HTTP request which is received in your express app). BUT - you are also integrating socket.io into your express app. Websocket data transmission is initiated via the HTTP protocol (where your cookie session middleware is trustfully adding the session info each time), but it then switches to the websocket protocol - where you don't have your session info anymore. You want your session info to carry on from the HTTP request which initiated socket data transmission into the socket data transmission itself. And so you get:
io.use(function(socket, next){
sessionMiddleWare(socket.request, socket.request.res, next);
});
The first line tells socket.io to use a middleware ("io.use"), a function which will be called each time you have data transmission via socket.io. You pass to this function two argument - socket and next. Next is simply a function which tells express.js to move on to the next piece of middleware once the present middleware has done it's thing. It's the "socket" argument which causes the confusion about this code, but here's what it does:
In the second line you are calling the function sessionMiddlWare (remember - it will be called each time an HTTP requests results in initiation of Websocket data transmission) and pass it three arguments: The third and last argument is "next", simply go to the next middleware once this middleware which initializes sessionMiddleWare has done its job.
The first argument (socket.request) is simply a reference to the HTTP request which initiated the socket data transmission (reference: https://socket.io/docs/server-api/#socket-request). This is where you accomplish what you set out to do, because this reference to the HTTP includes the session data - which is now included in your websocket transmission!
The second argument (socket.request.res) is the really puzzling one. It's task is to tell sessionMiddleWare if it should or should not save the session data for the transmission that just happened (reference). Notice that you don't necessarily want sessionMiddleWare to save the session data - you are most probably satisfied if the server and client have the right record of the data and so you can forget about the middle man (the sessionMiddleWare, that is).
Furthermore - This doesn't seem to work! developers trying to save the session data within the sessionMiddleWare report that it doesn't happen anyway (see the reference to the github thread in this paragraph). So you can pretty much just use:
sessionMiddleware(socket.request, {}, next);
and get the same results without the mysterious socket.request.res argument ;)
proof for this in the comment thread to the Answer in this stack overflow discussion.
Hope it's clearer now!

Express 4.x Prepend cookie to static contents?

Is it possible to set a cookie to a static content request using Express? For instance I'm trying to append the cookie "foo" to any request that doesn't have that cookie value set, before sending static contents such as index.html.
var express = require("express");
var cookieParser = require('cookie-parser');
var app = express();
app.use(cookieParser());
app.use(function(req, res, next){
if(!req.cookies || !req.cookies.foo){
res.cookie("foo", "bar");
}
next();
});
app.use(express.static('public'));
My problem is that this flat out doesn't work. I can set a cookie if I add send onto the end, but it either requires a dedicated url call, or terminates the response when thew original intended target was "index.html", then placed towards the front of the router.
app.get('/cookie',function(req, res){
res.cookie('foo' , 'bar').send('Cookie is set');
});
Do I need to do something like check every request, set the cookie, and then set a redirect for the same url to get the original indented request (index.html, etc)?
This looks weird:
if (!req.cookies || req.cookies.foo)
For one, req.cookies will always be defined by cookie-parser. If there weren't any cookies passed in the request, it will be an empty object (which will evaluate to true). Also, it looks like you want to set a cookie foo only if it's set already?
I think you want this instead:
if (! req.cookies.foo) {
res.cookie(...);
}

Node Express auth status

I have multiple routes, split into different files (my app consists of different "modules", which I maintain in separate folders. For each folder, there is an index.js file in which I manage the routes per module, and I require these in the app.js file).
For every route, I will require to check the auth, and pass the loggedIn status to the header of every page:
//Default variables for the ejs template
var options = {
loggedIn: true
};
res.render("home/home", options);
If the logged in status is true, then the user's name will be displayed. If not, the login / signup labels are displayed.
What is the best way to centralise this, so that I don't need to require the auth script in every of these index.js (route) files?
I need to be able to pass the auth status to the view via the options object (see example).
In your auth, module, use a middleware function. That function can check and store res.locals.loggedIn which will be available for any view that will eventually be rendered. Just make sure the app.use call executes prior to your other routes and it will work properly.
app.use(function auth(req, res, next) {
res.locals.loggedIn = true; // compute proper value here
next();
});
From what I understand you need to do this for every request.One common thing is adding this as middleware so that all the request gets this .
For Example :
var http = require('http');
var connect = require('connect');
var app = connect();
app.use(function(req, res) {
res.end('Hello!');
});
http.createServer(app).listen(3000)
Now for every request , Hello is printed . You could extract this as a module and reuse it across projects. Check here for more details

Is there a way to access jwt user information in unprotected endpoint in nodejs using express-jwt?

I'm using express-jwt to protect my endpoints, but I'd like an unprotected endpoint to show some extra information if the user is logged in. So I'm wondering if there is a way to access such user info in unprotected endpoint?
codes look like:
// unprotected endpoint
router.get('/:productId', function(req, res) {
// some ways to get user info??
if (req.user.userId) {
// add some extra fields into returning_data
// something like purchase history
}
res.json({data: returning_data})
}
Or if there is an alternative way to achieve this?
Looking at the code for express-jwt it appears that if you pass the option credentialsRequired: false on your express-jwt setup for the routes you want, it should allow access even if the token is not present.
Therefore, for example:
var expjwt = require('express-jwt');
app.use('/private', expjwt({ secret: "sssshhhhh!" }), apiRoutesPrivate);
app.use('/public', apiRoutesPublic);
app.use('/publicwithuser', expjwt({ secret: "sssshhhhh!", credentialsRequired: false }), apiRoutesPublicWithUser);
... where apiRoutesPrivate / Public / PublicWithUser contain the relevant routes for each.

Not cookie based session management in node.js

I am looking for a non-cookie based session management in node.js, something like pass a parameter in the URL like &session_id=. It will know that a session has expired when a request comes with an session_id. I've looked at connect library, but it looks that it is cookie based only.
Warning
Passing the session id as a GET parameter is considered bad practice. Why? It is dangerous because people don't usually care about session id and they will probably publish/share links with their session ids inside.
It's also a problem because when a user clicks an external link on your web, and goes to another site, that new site will be able to see the session_id in the referrer link.
So I don't think it is a good idea. Cookies are more secure.
Have a look at: Session Hijacking
For every request you receive, you will get all of the client cookies accordingly.
You can also set client cookies in the response HTTP headers using "Set-Cookie."
Using a GET parameter is unsafe. Any user could accidently share their session ID, but if you want 100% security, I'd share session IDs via cookies, and I would use HTTPS to prevent snoopers from stealing cookies.
You can use localstorage or sessionStorage..
almost same as cookie
not a cookie
better than a cookie!
More info: https://developer.mozilla.org/en-US/docs/Web/Guide/API/DOM/Storage
It's very -very- easy to use... in Js for example:
<script>
// check if Storage is avaible
if(typeof(Storage)!=="undefined") {
// Save data to local storage (no exiparion date)
localStorage.setItem("name_always", "bxx");
// Save data to the current session (removes when the tab is closed)
sessionStorage.setItem("name_now", "bxx");
} else {
// No Storage support...
}
// Access to stored data
alert( "For only now, my name is: " + sessionStorage.getItem("name_now"));
alert( "Every day, my name is: " + localStorage.getItem("name_always"));
</script>
Tags: javascript html5 local-storage session-storage
You can use sessions with a store in node.js. For example, you have express application and want to use session like system in your webapp. You can use connect-mongo module for this. This will let you store your session in db. In your app.js
var express = require('express'),
, mongoStore = require('connect-mongo')(express);
var app = express();
app.configure('all', function () {
app.use(express.session({
secret: "terces",
cookie: { maxAge: 24 * 60 * 60 * 1000 },
store: new mongoStore({
url: your_db_url
})
}));
app.use(function(req, res, next) {
res.locals.session = req.session;
next();
});
});
With basic code above, you have session in express that you can use it in your controllers and views directly. In your controller;
app.post('/blog/create/?', function(req, res, next) {
if (!req.session.user) {
next("You need to login in order to create blog!");
}
});
In your view, you can use session.user in order to generate profile menu for example.

Resources