I want to put user's password into request object for accessing it next request object. Is it secure?
For example :
We have a route like "http://localhost/my_bank".
And there are two middlewares before accessing to route.
First middleware checks user's password and if it is true puts password into request object and continues for second middleware.
Second middleware gets user password with request.password and continues the process.
If you're talking about the request object that is passed to a middleware handler such as in Express like this:
app.use((req, res, next) => {
// do something here
req.password = someData;
next();
});
Then, there's nothing particularly unsafe about that. In fact, if you were using express.json() or express.urlencoded() to parse an incoming form that contains the password, then that middleware already put the password into req.body.password or some similarly named field. Thus, it's already in the req object and this is a common usage.
So, there's nothing inherently unsafe about putting a password in the req object as long as you aren't passing the req object to functions/code that shouldn't have access to the password.
Related
I have a bug which has made me realize I clearly missing something important about express middlewares. I have something like this:
const checkAuth = ({ allowedRoles = [], targetUserId }) => {
return async (req, res, next) => {
console.log(targetUserId);
//Do checks
if(!allowedRoles.includes(req.user.role) return
targetUserId = req.params[targetUserId]
if(!allowedUsers.includes(targetUserId) return
return next();
};
};
app.get(
"/activity/:id",
checkAuth({ allowedRoles: ["locationAdmin", "orgAdmin"], targetUserId: "id" }),
async function (req, res, next) {
//Do things
});
});
The idea behind this middleware is the 'targetUserId'variable tells it which request parameter to look in for a value, then it can choose to authorize the request with the value it finds there. The middleware actually exists in it's own file/module if that makes any difference.
Here's what I expect to happen:
User loads url /activity/23 > "id" is logged
User loads url /activity/23 > "id" is logged
and so on until the end of time...
What actually happens:
User loads url /activity/23 > "id" is logged
User loads url /activity/23 > 23 is logged
User loads url /activity/23 > undefined is logged
User loads url /activity/23 > null is logged
item 4 will then repeat forever
My expectation is that each time checkAuth is called, there should be nothing in memory from it's last call. It's taken me a couple of hours to get my head around this, but what seems to be happening, is after the value of targetUserId is set within the middleware, the variable remains set in memory, and isn't changed when it gets called again with "id". This explains why the value logged to the console changes 3 times on repeat requests for the same page.
But why does it do this and how can I fix it?
The way your code is structured, checkAuth() is called once when your code is first run. That captures the arguments you passed it and then makes those available to the middleware function that checkAuth() returns and that middleware function is passed to Express where it is registered as middleware for this request handler.
That middleware function you return is then called by Express for each incoming request that matches this request handler. The arguments you passed to checkAuth() are available to that middleware function each time it is called.
If some code changes those arguments (like code inside the middleware itself changes an object or property passed), then those changes are persistent (in a closure) and future middleware will see those changes. So, if you need to modify those arguments for the purposes of one request, then you should make a copy of the data or make the modifications in a variable that is local to the internal middleware function.
I have some code from a tutorial and i am trying to understand it. I can't figure it out what's the purpose of this middleware function:
app.use((req, res, next) => {
res.locals.path = req.path;
next();
});
res.locals doc says:
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).
This middleware sets the path part of the request URL to res.locals object and call next middleware.
You can use the res.locals.path to access the value in your controller later
I am new to Node.js programming. I am having a big trouble as I keep getting same error in the following code. I can not understand what is the problem there.
Can't set headers after they are sent.
var mongoose = require('mongoose');
module.exports = function(req, res) {
var User = require('../../Schema/User');
User.count({ $and: [{ "username": req.body.username }, { "password": req.body.password }] },
function(err, count) {
console.log(count);
res.json(count);
});
};
You are calling next() in your route code essentially turning your login snippet into middleware and passing it down. You are getting this error because in your login code you are outputting with res.json and then still calling the next step with next. l.
Your issue is just that headers must come before any output. Whether you write or pass the data on in your middleware is up to you as long as you are aware of subsequent possible headers/writes.
But you may want to reconsider your setup - in general auth middleware would be used to verify that a user is logged on - perhaps checking a session cookie. If the user is ok then you can fetch (if needed) user data based on the cookie info (i.e. the _id) or redirect the user to a login page.
What you have here is the login route which doesnt really need middleware. Simply check if user is valid and either set a session cookie or tell them it's a no go.
Passport makes things easier. Check out this post. The underlying principle is the same I outlined above, it just makes it easier to get going.
I inherited a codebase where it looks like they run middleware in node with the following pattern for Oauth2 passport strategy
module.exports = function (router) {
router.get('/', function (req, res, next) {
passport.authenticate('type', object, function(err, info) {
//pass info object to next middleware
})(req,res,next) <---where does this go?!?
})
}
From my current understanding of the code base, this is actually the last function call in the middleware chain, so could I just add a piece of middleware to the bottom?
Does this sound like the right idea?
And just to clarify what I'm trying to do:
pass data from Oauth callback through middleware function by attaching it to the req
perform DB business logic (create or lookup account)
login with JWT
redirect
This appears to be the "custom callback" method of using passport's authenticate function. If you look at the documentation you can see how they expect it to be used. That said, I don't know what that second argument is supposed to be doing (the object) - it looks like a variable, but I don't see it defined anywhere, and I'm not sure the authenticate method takes arguments in that manner. Also, the custom callback takes three arguments: err, user, and then info... which might trip you up.
Okay, so now to your actual question of "could I just add a piece of middleware to the bottom?" Sort of? The fact is, you're in a routing middleware at that point. If it matches and auth is successful, then you should do whatever code for that route is required inside the custom callback. That's the point of this way of doing things. Alternatively you could use passport.authenticate as a piece of middleware itself (it returns a middleware function usable in the CommonJS pattern.
If you don't want to change up the code, then you could just do this:
module.exports = function (router) {
router.get('/', function (req, res, next) {
passport.authenticate('PICK A VALID TYPE', function(err, user, info) {
// this custom callback will be executed once auth completes
// (either successfully or not
// put code in here to perform DB business logic, login, and redirect
})(req,res,next); <--- this executes the passport.authenticate middleware
})
};
I've been working on creating a better architecture for rest api in express and node. Let's say I have 3 methods in my route middleware -
router.post('/users/:id', [
UserService.getUserById,
UserController.setUser,
MailerService.sendSubscriptionMail
]);
I am setting up req.session.user in call to UserService.getUserById and then using that to set req.session.result in UserController.setUser. Now I am sending a mail to this user using the data stored in req.session.result.
UserService -
exports.getUserById = function(req, res, next) {
.
.
req.session.user = data;
.
.
};
module.exports = exports;
UserController -
exports.setUser = function(req, res, next) {
.
.
req.session.result = req.session.user;
.
.
};
module.exports = exports;
MailerService -
exports.sendSubscriptionMail = function(req, res, next) {
// Using req.session.result here to send email
};
module.exports = exports;
Now I have two questions regarding above process -
(a) Is there any chance that a new http req to another route (which also has these kind of methods which can modify req.session) can modify the req.session.result and MailerService.sendSubscriptionMail does not get the data which it needs to send to the user or will that req object will be completely different from this one in the memory?
(b) Is there any other method to transfer data between middleware rather than setting up req object?
Is there any chance that a new http req to another route (which also
has these kind of methods which can modify req.session) can modify the
req.session.result and MailerService.sendSubscriptionMail does not get
the data which it needs to send to the user or will that req object
will be completely different from this one in the memory?
The req object is specific to this request. That object cannot be changed by another request. But, if the session in req.session is a common shared sesison object that all requests from that particular user share, then req.session.result could be changed by another request from that user that is getting processed at around the same time (e.g. interleaved within various async operations).
If you want to make sure that no other request from this user could change your result, then put it in req.result, not req.session.result because no other requests will have access to req.result.
Is there any other method to transfer data between middleware rather
than setting up req object?
The req or res objects are the right places to share info among middleware handlers for the same request as they are unique to this particular request. Be careful with the session object because it is shared among multiple requests from the same user.
Another possible way to share the data among your three handlers is to make a single middleware handler that calls all three of your middleware handlers and then share the data within that single function (e.g. passing it to the other handlers).
For example, you could change the calling signature of your 2nd two methods so you can get the data out of setUser() and then pass it directly to sendSubscriptionMail() without using the req or session objects to store it.
router.post('/users/:id', [UserService.getUserById, function(req, res, next) {
UserController.setUser(req, res, function(err, result) {
if (err) return next(err);
MailerService.sendSubscriptionMail(result, req, res, next);
}]);
});