restricting some routes to localhost

4,138 views
Skip to first unread message

Colin Bester

unread,
Jul 17, 2014, 10:16:54 PM7/17/14
to expre...@googlegroups.com
I am looking to restrict a sub-set of routes to only respond to requests from localhost. Only way I can see to do this is by comparing all IPV4 and IPV6 possibilities for relevant routes but this looks and feels pretty untidy. I was wondering if anyone had any pearls of wisdom on how to do this as I'd prefer to not split my application into two different servers. BTW, I am running on a ARM7 platform and don't have the option of running NGINX.

~C

Jason Crawford

unread,
Jul 17, 2014, 11:29:00 PM7/17/14
to expre...@googlegroups.com
I hate to be the guy who answers a request for help by questioning why you want to do the thing in the first place, but—in this case it really feels to me like there's probably a better way to accomplish whatever it is you're after. What's your goal here?

-Jason


On Thu, Jul 17, 2014 at 7:16 PM, Colin Bester <bester...@gmail.com> wrote:
I am looking to restrict a sub-set of routes to only respond to requests from localhost. Only way I can see to do this is by comparing all IPV4 and IPV6 possibilities for relevant routes but this looks and feels pretty untidy. I was wondering if anyone had any pearls of wisdom on how to do this as I'd prefer to not split my application into two different servers. BTW, I am running on a ARM7 platform and don't have the option of running NGINX.

~C

--
You received this message because you are subscribed to the Google Groups "Express" group.
To unsubscribe from this group and stop receiving emails from it, send an email to express-js+...@googlegroups.com.
To post to this group, send email to expre...@googlegroups.com.
Visit this group at http://groups.google.com/group/express-js.
For more options, visit https://groups.google.com/d/optout.

Colin Bester

unread,
Jul 18, 2014, 9:34:10 AM7/18/14
to expre...@googlegroups.com
I hear you and appreciate you hearing me out. A lot of the reasoning behind this is to meet the business requirements and I do realize there are several ways to meet objective.

I have small footprint device with a single application that is serving a core RESTful api which interacts at low level with device providing control functionality. Local to this machine is another web application that accesses this api and provides basic interaction/feedback via a small touchscreen using browser running in kiosk mode and a web service to remote web browsers.

The RESTful api, in addtion to providing service to the local running web application also provides service to external smart devices which provide their own version of GUI and higher end application logic.

In summary and not going into too much detail or business reasons;
  • For RESTFUL api application, I am needing the locally running web application to be able to access RESTful api without needing keys but I want the external applications to have to be registered and have necessary keys/hmac etc in place in order to access the RESTful api
  • For web service application I want local access (the kiosk mode browser) to have access (think user auto login), but external devices to be managed via user login.

One solution is to also have the locally running web application also have a key, but this increases the number of keys/devices to be managed and I am looking to simplify and ease scalability.

Hope this makes sense.

Paul Vencill

unread,
Jul 18, 2014, 11:20:53 AM7/18/14
to expre...@googlegroups.com
Well, like Jason I'm not sure I agree with your approach, even with what you've explained. If it were me, I'd probably put the business logic in one module, then have the Express app do nothing but expose the business functionality as REST endpoints, and have a CLI application (or whatever) that do the same thing but expose the "private" routes via command line stuff or perhaps a local socket connection.  Then your "localhost" stuff can be done only on the box it's installed on.

That said, if you really must do it as one app and it really must all be RESTful, then you could have all the local machine calls be to localhost:3000 (or whatever your port number is).  Then your middleware on the routes in question could just look at the req.headers.host value, which will be localhost:3000 (or whatever the port is) and a little string parsing will let you accept or reject the request just like any other auth middleware would.  Something like this:

function localOnly(req,res,next){ 
    var hostmachine = req.headers.host.split(':')[0];
    if(hostmachine !== 'localhost')
         return res.send(401);
    next();
}

then your routes in question coudl be mounted like:

app.get('/localPrivateStuff', localOnly, yourRouterHandler);

Honestly, though, if it were me I'd either split the functionality out into different modules as described above, or else have the local user have a token just like remote users do, despite your desire to not do that.  


Colin Bester

unread,
Jul 18, 2014, 11:36:47 AM7/18/14
to expre...@googlegroups.com
Maybe I confuse the issue discussing the different modules running on the device. To simplify, think of one module serving RESTful service where I want all localhost connections to be accepted but require some remote connects to be authenticated.

Presently I am doing this by using var remote = req.ip || req.connection.remoteAddress to access the connection IP address and simply comparing to executing test if ((remote === '::1') || (remote === 'localhost')) to see if this is remote connection or not. I was worried about complexity of checking for localhost, 127.0.0.1, ::1, and actual IP addresses and doing all the comparisons but for now am simplifying to only supporting ::1 or localhost.

Colin Bester

unread,
Jul 18, 2014, 3:33:41 PM7/18/14
to expre...@googlegroups.com
One of my issues was in how to effectively manage an if then, else if then else check with routing.

First check if request is from local, if not check if authenticated, if not reject.

Using multiple routes and next('route') solved my issue.

For example:
app.get('/test', isLocal, function(req, res) {
console.log('local req')
//call function
res.send("OK");
});

app.get('/test', isAuthenticated, function(req, res) {
console.log('remote req')
//call function
res.send("OK");
});

function isAuthenticated(req, res, next) {
console.log("check authenticated")
        if (some test for authentication)
    return next();
        else
            res.status(40x).send("Error, not authenticated").
}

function isLocal(req, res, next) {
var remote = req.ip || req.connection.remoteAddress
console.log("in islocal")
if ((remote === '::1') || (remote === 'localhost'))
return next();
else 
return next('route'); //call next /test route to handle check on authentication.
}

Nathan White

unread,
Jul 18, 2014, 4:04:18 PM7/18/14
to expre...@googlegroups.com, expre...@googlegroups.com
You can stack middleware.

app.get("/test", isLocal, isAuth, route)
--

Colin Bester

unread,
Jul 18, 2014, 4:12:01 PM7/18/14
to expre...@googlegroups.com
Correct you can but then the required logic would be wrong as it would run isLoca()l AND isAuthenticated() if isLocal() passes - where I want to only run isAuthenticated() if isLocal() fails (i.e. access is from remote machine)


On Friday, July 18, 2014 3:04:18 PM UTC-5, nwhite wrote:
You can stack middleware.

app.get("/test", isLocal, isAuth, route)

Paul Vencill

unread,
Jul 18, 2014, 4:19:38 PM7/18/14
to expre...@googlegroups.com

It'd be cleaner to have the isLocal function just set a property on req and then have the isAuthorized function use that as part of its logic. Then everything can be done inline as proposed.

Colin Bester

unread,
Jul 18, 2014, 4:26:13 PM7/18/14
to expre...@googlegroups.com
I like that idea - thanks all!

~C

On Jul 18, 2014, at 3:19 PM, Paul Vencill <paul.v...@gmail.com> wrote:

It'd be cleaner to have the isLocal function just set a property on req and then have the isAuthorized function use that as part of its logic. Then everything can be done inline as proposed.


Internet Disclaimer
_________________

This message (including any attachments) contains confidential information intended for a specific individual and purpose, and may be protected by law. 
If you are not the intended recipient, you should delete this message and are hereby notified that any disclosure, copying, or distribution of this message, or the taking of any action based on it, is strictly prohibited.
_________________



Nathan White

unread,
Jul 18, 2014, 4:27:10 PM7/18/14
to expre...@googlegroups.com

function isLocal(req,res,next){
    if(local_test) req.auth = true;
    next();
}

Your logic for local is "grant auth" so don't have isLocal fail, just pass. If it is local set a flag so it can pass your isAuth middleware.

Colin Bester

unread,
Jul 18, 2014, 4:37:10 PM7/18/14
to expre...@googlegroups.com
Got it, thanks!

darren

unread,
Jul 19, 2014, 9:12:55 PM7/19/14
to expre...@googlegroups.com
You can put the routes that are private into their own route module and spin up an express server that is bound to a local or private interface rather than the public-facing IP. The private app can include both private and public routes. More details on splitting routes for private / public access is here on a similar thread (https://groups.google.com/d/msg/express-js/oujexQBKPr4/bBd4ar-vOmoJ).

hope this helps.
Reply all
Reply to author
Forward
0 new messages