Controlling/Restricting User-specific content in Mongo-Database - node.js

I'm wondering how to control/restrict access from different users to their content stored in mongodb (accessed via mongoose). Let's say there is a data-model to store last wills for users.
My approach would be:
Login: authenticate via username and password, store username in session.
Middleware: Check Login-Status, query user-model for the stored username and return the user id, attach it to req-object (req.userId)
When hitting the route to get actual content (the last-will-model): query the will-model with two conditions: matching willId and matching userId (which is also stored in will-model)
Is this in any way reasonable or even save? Couldn't find any best-practises, all the examples basically end with authentication.

Steps 1 and 2 can be covered by using passport-local, although it's not too hard to implement manually.
Step 3 is reasonable, given that a will belongs to a user and both willId and userId are required to determine if that user should have access to a particular will document.
Since security is based on session id's, you should obviously use HTTPS and use httpOnly and secure session cookies.

With any of the three ways you can implement authorization, IMO the option I would choose is to use a Middleware.
It would be a cleaner option, with little impact on the code
functionality and easy to maintain for future changes, also separates
the concept of authentication and authorization.
I've never used, but have in mind to use this package in a project that I have to make. You can define your rules and then use it on specific routes.
app.get('/', *user.can('access home page'), function (req, res) {
res.render('private');
});
app.get('/private', *user.can('access private page'), function (req, res) {
res.render('private');
});
app.get('/admin', *user.can('access admin page'), function (req, res) {
res.render('admin');
});
*Predefined rules

Related

pass session variables to another domain

It seems this cannot be easily done...if at all.
Suppose I have 2 domains, www.mydomain.com and www.mydomain.org. Each domain uses a Node.js/Express back-end and in addition both use the "express-session" module to create session information. I wish to be able to have a user 'log in' while on one domain and have that session information pass to the other when navigation is made to the second domain.
Each domain has a 'catch-all' route that displays a 'splash' page. This is signified by the following route:
app.get('/', function (req, res) {
//do stuff and display 'splash' page...
}
I thought to pass the session information using a route that has a parameter containing the 'session' variable, and using that to set the 'logged in' user on the second domain. For example:
app.get('/user/:client', function (req, res) {
req.session.subscriber = req.params.client; //set the 'logged in' user on the second domain
//do stuff and display 'splash' page...
}
The problem is that BOTH routes seem to be called when using the route with the parameter...I suppose this makes sense since the initial route is activated using a backslash ("/")...Is there some way to correct this?
Any help about cross-domain express-session variable 'sharing' would be greatly appreciated. Thank you in advance.

Hiding the JSON payload from /api and auth/ routes

Is there a way to protect the api route when a user enter that in the url? Please see my screen shot. I know there's a way to authenticate a user in the backend using a middleware but it seems like if the data can be viewed publicly, the JSON payloads can also be viewed publicly. I'm still new to this, so forgive me if this question has already been asked. I use Node.js, React, Express and Sequelize.
I'm assuming that you do not want your /api/users route to be accessible to the public, I think this solution should work, although there might be better solutions.
You can try protecting specific routes based on the role of the user. I suggest you add a user_role field to your user schema, and create a middleware function that only allows logged in users with a specific role to access the route, as shown in the pseudo code below:
function (req, res, next) {
// Check if user is logged in and is assigned the role you want to allow.
if(user is logged in) return next();
else throw error;
}

How to secure an open REST API from abuse in Node.js?

For example, I have a REST api endpoint written in Node.js. It can be accessed from a webpage for non-technical users, and it can also be accessed through command line using the curl command. It doesn't require any credentials to access it because it is intended to be open for anyone to access it. The problem I am trying to solve is how can I prevent someone maliciously access this REST API endpoint, for example pinging this api endpoint over and over again, or how to prevent ddos attacks.
Not necessary a programming question, let me know if there is a better place to ask this.
Setup Rate Limiting if you cant have an auth on it.
You can use this if you are using express https://www.npmjs.com/package/express-rate-limit
Preventing DDOS is not that easy without using solutions like CloudFlare.
To secure your REST api, you can use middleware if you use express
const checkAuth = (req, res, next) => {
// logic for checking auth
if (authorized) {
return next();
}
res.status(401).send('NEED AUTH');
};
router.post('/login', checkAuth, (req, res, next) => {
// actual logic for login
});
Update: regarding #Akarsh's answer,
you can use multiple middleware before actual logic. For example, one for auth check, and one for rate limit
router.post('/logic', checkAuth, rateLimit, (req, res, next) => {});
You say you want it to be open, but then you say you want it to be sort of open!
Throttling / auth tokens. Choose at least one, pref both.
Pinging and DOS attacks are different and have nothing to do with your API as such. Unless your info is valueable / highly competitive, something as simple as IP banning will go a long way.

Express JS routing based authentication

I have created node js app using express framework.
I have created middleware for restricting access to some routes.
Middleware actually works fine. but i have difficulties in displaying data.
Suppose In My app i have created route for display list of countries('/country/master')i.e html page which is using internally different/default route ('/country/') to get data from mongoDB.
In this case user will not able to see data cause i have not given permission to "/" routes. but i want to display data but not allow him to make use of "/" route to check data.
How can i deal with this case ????
The answer depends on your authentication strategy i.e. are you using session identifiers, access tokens, etc.
In either case I suggest that you break out the credential exchange (aka login) from the authentication. They should be separate middleware functions. Below is an example of what this looks like.
While this answers your question, specific to ExpressJS, it does leave out a lot of other details that matter when you are building an authentication system (like how to securely store passwords). I work at Stormpath, we provide user management as an API so that you don't have to worry about all the security details! It's very easy to integrate our API into your application, using the express-stormpath module. You'll have a fully featured user database in minutes, without having to setup mongo or a user table.
All that said, here's the example:
/* pseudo example of building your own authentication middleware */
function usernamePasswordExchange(req,res,next){
var username = req.body.username;
var password = req.body.password;
callToAuthService(username,password,function(err,user){
if(err){
next(err); // bad password, user doesn’t exist, etc
}else{
/*
this part depends on your application. do you use
sessions or access tokens? you need to send the user
something that they can use for authentication on
subsequent requests
*/
res.end(/* send something */);
}
});
}
function authenticate(req,res,next){
/*
read the cookie, access token, etc.
verify that it is legit and then find
the user that it’s associated with
*/
validateRequestAndGetUser(req,function(err,user){
if(err){
next(err); // session expired, tampered, revoked
}else{
req.user = user;
next();
}
});
}
app.post('/login',usernamePasswordExchange);
app.get('/protected-resource',authenticate,function(req,res,next){
/*
If we are here we know the user is authenticated and we
can know who the user is by referencing req.user
*/
});
You can positioning of middleware in you app.for example:-
app.get('/country/master',function(req,res){
})
app.use(function(req,res){
your middle ware for providing authentication
})
// other routes where authentication should be enabled
app.get('other urls')

Group/rule-based authorization approach in node.js and express.js

What are good strategies for role-based authorization in express.js? Especially with express-resource?
With Express-resource there are no handlers, so I think there are three options:
Use a middleware
Pass the authorization function to the resource and check each resource request separately
Check authorization with every request right after authentication
Are there any other solutions?
Group/Role-based authorization is a pretty antique approach. Are there newer methods of access control? If not, how can role-based authorization be applied to node.js? Where to store group-rule relationships (with NoSQL/CouchDB/Redis)?
As an example, the structure:
/
/forums
/forums/threads
Each resource with index, new, create, show, edit update and destroy. Some people can edit/delete etc. threads and forums, some people shouldn't.
I would say that it's hard to solve this in a clean manner using express-resource, since it doesn't allow for route-specific middleware (at least not in a clean way).
I would opt for a similar layout as an express-resource module, but route it with plain old express. Something like this:
// Resource
var forum = {
index: // ...
show: // ...
create: // ...
update: // ...
destroy: // ...
};
// Middleware
var requireRole = function(role) {
return function(req, res, next) {
if('user' in req.session && req.session.user.role === role)
next();
else
res.send(403);
}
};
// Routing
app.get('/forums', forum.index);
app.get('/forums/:id', forum.show);
app.post('/forums', requireRole('moderator'), forum.create); // Only moderators can create forums
app.delete('/forums/:id', requireRole('admin'), forum.destroy); // Only admins can delete forums
UPDATE: There have been ongoing discussions regarding route-specific middleware in express-resource, e.g. here. The prevailing view seems to be to have an array per action, e.g.:
var forums = {
index: [ requireRole('foo'), function(req, res, next) { ... } ]
};
You could take a look through the pull requests and see if there is anything you could use. I totally understand it, of course, if you don't feel comfortable with that. I'm pretty sure we will see something like this in express-resource in the future.
The only other solution I can think of is along the lines of Jan Jongboom's answer, which would be to mount the resources with express-resource, but have middleware attached "outside" of that, something like:
app.delete('*', requireRole('admin')); // Only admins are allowed to delete anything
app.put('/forums/*', requireRole('moderator')); // Only moderators are allowed to update forums
But I regret that this leaks URLs all over the place.
I have been researching the same question and have come across a few good modules. I have been focusing on the node-acl package that can be found here. https://github.com/optimalbits/node_acl.
This package seems to have implemented the ACL pattern in a very understandable way and has provided ways to easily integrate it into your node/express application.
Firstly, you'll want to define your resources, roles, and permissions.
For example, the resources can be:
/
/forums
/forums/threads
The roles can be
public
admin
user
john
jane
In this example, the roles john and jane can map to actual user accounts, but they will inherit all the permissions of the user role.
The permissions on the resources
create
show
update
destroy
Or your standard CRUD operations.
Now that those have been defined, we can take a look at how it would look to set up the acl using node-acl. These notes are derived from the documentation
import the package
var acl = require('acl');
Set up your backend. My app is using mongodb, but the node-acl package does support other storage mechanisms
acl = new acl(new acl.mongodbBackend(dbInstance, prefix));
My app is using mongoose so dbInstance would be replaced with mongoose.connection.db
Now lets add our roles to the ACL. In node-acl, roles are created by giving them permissions. Its like killing two birds with one stone (no birds are actually harmed)
acl.allow('admin', ['/', '/forum', '/forum/threads'], '*');
acl.allow('public', ['/', '/forum', '/forum/threads'], 'show');
acl.allow('user', ['/', '/forum', '/forum/threads'], ['create', 'show']);
Lets assume a new resource is created by john, we will add a new record that allows john to also update and delete that resource.
acl.allow('john', ['/forum/threads/abc123'], ['update', 'delete']);
My application is also using express, so I will use the routing middleware approach to check routes. In my routing configuration, I would add the line
In most express configurations, this looks like for the pos
app.post('/', acl.middleware(), function(req, res, next) {...});
app.post('/forums', acl.middleware(), function(req, res, next) {...});
app.post('/forums/:forumId', acl.middleware(), function(req, res, next) {...});
app.post('/forums/threads', acl.middleware(), function(req, res, next) {...});
app.post('/forums/threads/:threadId', acl.middleware(), function(req, res, next) {...});
When no parameters are passed, this will check if the role defined in req.userId is allowed to execute the http method on the resource identified but the route.
In this example the http method is post, but it will do the same thing for each http idenitified in your configuration.
This raises the question, about the permissions defined earlier. To answer those questions, we would have to change the permissions from
create
show
update
destroy
To the conventional
post
get
put
delete
Although this example shows everything hardcoded, the better practice is to have a management interface for your permissions so they can be created, read, updated, and deleted dynamically without having to modify your code.
I like the node-acl plugins approach as it allows for very fine grained permission-role assignments using a very straight forward and flexible api. There is a lot more in their documentation, my example shows were I am with the package.
Hopefully this helps.
Connect-roles is quite good, simple and the documentation is also very clear.
var user = roles;
app.get('/profile/:id', user.can('edit profile'), function (req, res) {
req.render('profile-edit', { id: req.params.id });
})
app.get('/admin', user.is('admin'), function (req, res) {
res.render('admin');
}
In express you can add a handler that hooks into every operator (http://expressjs.com/guide.html#passing-route control) where you can do precondition validation. Here you can retrieve the role for the user and restrict access based on the HTTP verb (PUT, DELETE, etc.) or the URL (param('op') is 'edit' or so).
app.all('/user/:id/:op?', function(req, res, next){
req.user = users[req.params.id];
if (req.user) {
next();
} else {
next(new Error('cannot find user ' + req.params.id));
}
});
I wrote a module as non-explicit routing middleware. Works well with express-routes.
Gandalf on GitHub
You can try Casbin: https://casbin.org/, it has a Node.js version. It also has a Express.js middleware called express-authz: https://casbin.org/docs/en/middlewares

Resources