Access set cookies in response object - node.js

I'm checking and setting a couple of cookies in the middleware before hitting the route. After hitting the route, inside the handler, I'm trying to access the aforementioned set cookies but the response object has no accessor for these set cookies.
# similar to req.cookies.cookie_name to access cookies sent by the client
stored_value = res.cookies.cookie_name # this method doesn't exist
The response object exposes a getHeader method, using which I attached a simple cookie parser on response.getHeader('Set-Cookie') to the response object.
app.use (req, res, next) ->
#
# returns a hash of cookie_name: cookie_value,
# or cookie_value if cookie_name is sent as an argument
#
res.jit_cookies = (cookie_name) ->
cookies = {}
for cookie in this.getHeader('Set-Cookie')
tokens = cookie.split(';')[0].split('=')
cookies[tokens[0]] = tokens[1]
if cookie_name? then cookies[cookie_name] else cookies
next()
So now I can access the cookies I set anywhere I have access to the response object.
res.jit_cookies() # returns a hash of all cookies set
res.jit_cookies('lang') # returns the value of the 'lang' cookie
I'm using cookies so that the state of the response is bound to the response object which is later accessed in many places.
Is this okay to do? Are there other (and better) ways to track and access the same information that I'm trying to use cookies for?

There already is a cookie-parser middleware that parses cookies for you and puts them in req.cookies.
As far as accessing the req when you only have res, you can access res.req.

You need to use a middleware called: "cookieParser"
If you are using Express v3.X:
app.use(express.cookieParser());
instead if you are using 4.X you need to also import it and use it as follows:
var cookieParser = require('cookie-parser')
app.use(cookieParser())
Of course, for the second option you need to first install the package:
$ npm install cookie-parser
In that way you can get access of cookies like:
req.cookies // returns an object
req.cookies['yourCookieName']

Related

Where is req.variable stored?

Similar question (but NOT a duplicate): How do i store request-level variables in node.js?
Consider this following code:
const express = require('express');
const app = express();
app.get('/', (req, res) => {
req.someVariable = "Hello";
res.send(req.someVariable + ' world!');
});
Where is req.someVariable stored? In a cookie? Does this apply for the user only or everyone? Also, what's the difference between these and storing them in sessions/cookies?
In addition to req being just a javascript object variable, stored in memory, do note express has a res.locals object variable that persist through the request/response cycle.
If you want to store any user information, you should be using the res.locals object so you do not accidentally overwrite other important objects.
res.locals
An object that contains response local variables scoped to the
request, and therefore available only to the view(s) rendered during
that request / response cycle (if any). Otherwise, this property is
identical to app.locals.
This property is useful for exposing request-level information such as the request path name, authenticated user, user settings, and
so on.
http://expressjs.com/en/5x/api.html#res.locals
app.use(function (req, res, next) {
res.locals.user = req.user
res.locals.authenticated = !req.user.anonymous
next()
})
Note: res.locals on it's own is not sent together with the response (e.g. res.send). It's only accessible in your nodejs app.
Cookies
Cookies are information bits that you want to send to the client's browser (stored in browser memory). The client can then send the cookie back to your nodejs app. These are different from req and res properties.
Cookie can store for example, an authentication token, which can be stored in the client's browser, and provided to the nodejs app on every request.
For security, you can use a httpOnly cookie which cannot be modified by browser javascript.

Node express static with csrf

I'm trying to use csurf in nodejs, express and React Project. My csurf is working fine right now, but I want to double check if I did it right.
Here is my nodejs router and middleware structure:
app.use(cookieParser());
app.use("/api/...") // routes that don't need csrf
app.use("/form/...",csrf({cookie:true})) // form path with csrf middleware
app.use(express.static("/img")) // image folder which doesn't need csrf
app.use(csrf({ cookie: true })); // enable csrf for the rest of the app
app.all("*", function(req, res, next) {
res.header("X-CSRF-Token", req.csrfToken()); // set csrf to header
return next();
});
app.use(express.static("/SPA")); // frontend project
Current behavior:
When I first enter my web project, I have X-CSRF-Token: xxxxx and set-cookie: _csrf=yyyyy; Path=/ in my response headers
When I refresh my page, Cookie: _csrf=yyyyy; appears in the request headers section.
When I refresh my page, X-CSRF-Token changes to a different value.
Only X-CSRF-Token value passed through post request, _csrf value inside cookie throw 403.
Question:
A. I believe setting app.use(csrf({ cookie: true })) is redundant, but when I set it to false or removed app.all(...) part, the app throw 403 / Internal Server Error. How to fix it?
B. X-CSRF-Token changes everytime I refreshed my page, it's obviously a normal behavior since I put it in the header, but does it defeat the purpose of csrf? Since my project is SPA, do I really care that much?
Please point out if there were anything wrong with the logic / behavior ?
Thanks.
Since my project is SPA, do I really care that much?
If a client app (SPA or not) sends some data to the backend and the data changes backend's state either directly or indirectly, for example via an action performed by backend on client's behalf, then CSRF vulnerability exists and you should care unless SPA framework like Angular takes care of CSRF protection. Using SPA doesn't change anything with respect to CSRF, it doesn't help and it alleviates nothing.
With cookie-parser middleware the csrf middleware works like that:
Checks for its cookie with a predefined name in the incoming request. If not found then generates a secret key and puts its value (decorated a bit) into the response cookie hoping to find it in the next request. So the secret is not a secret anymore.
If cookie not found and the incoming request is mutating like POST (e.g. not GET, HEAD ...) then fail it e.g. send 403 back with cookie set. If non-mutating like GET then processing is finished.
If cookie found then check for the second piece of data, by default in few places including HTTP header with a predefined name. If not found or found and incorrect then fail incoming request. Otherwise processing is finished.
To ensure this check is successful you are responsible for 2 steps:
- on the backend call req.csrfToken() to obtain this second piece of data and store in the response. You have chosen to store it in HTTP header, it's fine. But you could have used any header name. Or you could have used <meta> tag in the <head> section.
- on the client take the second piece of data from the above header or <meta> tag in the backend response and put it into the request you are about to send assuming the request is mutating e.g. POST, PUT, etc. Furthermore, you need to put it into one of the predefined places in the request where csrf middleware searches by default.
Regarding your code:
1. The client code responsible for the second step is missing.
2. On the backend call csrf({options}) function once and store the returned value. You have called it twice. The return value, let's call it retValue, is the configured csrf middleware, use it as needed:
app.post(/<path>, retValue, ...req, res, next) => {...
3. As for the options, set httpOnly: true. Additionally, in production set secure: true:
csrf({cookie: {
httpOnly: true,
secure: true
}})
A. I believe setting app.use(csrf({ cookie: true })) is redundant,
but when I set it to false or removed app.all(...) part, the app
throw 403 / Internal Server Error. How to fix it?
By setting app.use(csrf{cookie:true}) before your routes you tell your app to pass each request that you get through csrf middleware (except those higher than this command). This middleware is supposed to do 3 things.
First is to set csrf cookie, if it's not present yet. This cookie is a secret which is needed to create/verify csrf tokens.
Second is to create new token when you call req.csrfToken().
Third is to verify tokens for all non-GET/HEAD/OPTION requests.
Also it's important to understand what you do with this command:
app.all("*", function(req, res, next) { res.header("X-CSRF-Token",
req.csrfToken()); // set csrf to header return next(); });
All your requests (get, post, put etc etc) they generate new token on the basis of the secret you have in your cookie. Same secret generates random tokens, as random salts are used for this purpose.
So in case you remove app.all part with req.csrfToken() you will not be generating any tokens, so verification will fail. And in case you remove app.use(csrf) part you will not be able to verify anything as this part does verification and you will fail to issue tokens as well. Because in other words the middleware will be turned off. So you can't remove any of these two commands as they serve different purpose.
B. X-CSRF-Token changes everytime I refreshed my page, it's obviously a normal behavior since I put it in the header, but does it defeat the purpose of csrf? Since my project is SPA, do I really care that much?
The purpose of csrf tokens is to verify whether request came from your website, because otherwise the client will have cookie only, but no token in the header. Pressing link initiating some actions on your website, but being on a different website will not generate csrf token for the client.

using csurf with session in express

I'm writing a single page application with MEAN stack, and using express-session with redis for session management.
I want to use scrf token in my client's cookies.
the problem is when I add csurf middleware, it set a session with name csrfSecret in redis, but how can I send it in cookie to client?
middlewares :
app.use(csrf({}));
app.use(function(req, res, next) {
res.cookie('csrf-token', req.csrfToken());
return next();
});
and csrf-token is sending to client but it don't do anything.and I receive 403 error from module.
thank you for any answer or idea.
If you want to create a csrf cookie in the client you have to use the following:
app.use(csrf({ cookie: true })
This will create a token in the client. If you do not pass any options to the csrf function it will use req.session. If you want to save the cookie client-side, remember that you will need to use cookie-parser module.
You can find more information in the github link to the project: https://github.com/expressjs/csurf

Set Cookie fails in ExpressJs

I have a problem in Express 4.x.I can't set any cookies. I want to set a cookie via Ajax request, i do the request, my server-side res.cookie() is executed, in my response headers i can find my 'set-cookie' header with the specific name and value, but nothing happens, the cookie is not registered. I have no HttpOnly or secure flag.
Cookie set example :
res.cookie('my_cookie','value',{maxAge:500,secure:false,httpOnly:false});
What i've noticed is that if i set maxAge 500 for example, my cookie expiration date from response headers is about 5 hours ago, so i tried to add a bigger value, but nothing happened.
It is like my set-cookie header is ignored. I don't use AngularJS, just jQuery.
If i put the set-cookie content in document.cookie from js console, the cookie is registered..
Thanks in advance and sorry for my bad english .
Version 4.0 removed a lot of the convenience middleware from the library for a more modular architecture; in this case you need to reference the cookie-parser middleware. Without it req.cookies is just an empty {}.
$npm install cookie-parser
var express = require('express')
var cookieParser = require('cookie-parser')
var app = express()
app.use(cookieParser())
You also need it to sign cookies:

Is a session always created when using express js?

Assuming one sets the cookieParser in a Node application using Express JS, does it mean that a session will always be created if none is not available in the incoming request?
self.app.use(express.bodyParser());
self.app.use(express.cookieParser());
self.app.use(express.session({...]);
In other words, does req.session will ever be null or undefined?
Yes, the session middleware will put a session object on each request given your code above. Not the cookie parser has one well-defined job: parse the cookie header from HTTP header key/value to JS object. End of story. It's the session middleware that handles creation and population of the session object.

Resources