httpNode top level middleware to replace basic-auth

Currently, if we set httpNodeAuth in settings.js, a middleware function using basic-auth is applied at the top-level of the httpNode express app. It protects all routes beneath it including those of the http in node, dashboard, and any routes added by other nodes to httpNode. And depending on how you define httpNodeRoot and httpStaticRoot, it may also protect static routes.

httpNodeAuth: { user:"user", pass:"$2b$14$B.jppbe..."},

If the httpNodeAuth property can also except a middleware function or array of middleware functions, then we can inject our own custom authentication system at the same location where the basic-auth middleware would have been added at the top-level:

httpNodeAuth: [
  httpBlocker, // blocks ip(s) that were dynamically banned
  httpRouter, // express router handles login/logout routes
  httpSession, // attaches session to all routes not matched in httpRouter
  httpVerify, // verifies session has authorization to access resource
],

I have implemented this on my system for the last couple months and it is working well with the following points:

  • backwards compatible / non breaking change
  • does not affect httpAdmin authentication
  • browsers offers to save and populate the user/pass in the login form
  • advanced features such as tracking and terminating socket. io connections
  • only allowing user to be logged in from 1 device at a time by managing sessions
  • dynamically blocking ip addresses for multiple failed login attempts
  • function node receives event for failed login attempts and then can send alert msg to admin

And I must point out that is not equivalent to using httpNodeMiddleware, since that only adds middleware functions to the individual http in node routes and not at the top level. The name of that property implies middleware is added to the httpNode, but unfortunately it does not. It probably should be called httpInMiddleware, but maybe it's too late to change that without creating deprecation warnings and all that noise.

Also, being able to create a custom auth system is not a substitute for using other software such as iptables and reverse proxies, but it should work in conjunction with them. For example, if an ip gets blocked due to multiple failed login attempts, the function node listening to the events can send a msg to a file node and write the ip to the blocked list while also sending an alert email to the system admin. Perhaps some cron process can occasionally read from that file and update iptables with the current list of naughty ip addresses, etc.

It would only be a few lines of code to change and I would be more than happy to submit the pr.

4 Likes

Agree that it would seem sensible to have the ability to use a function instead of a simplistic user id/password for the httpNodeAuth. Would bring it more into line with adminAuth.

However both the node-red docs and the settings.js file would need updates to reflect any changes. Would be good to have the node-red security docs updated to include something like your last but 1 para. And also to add the warning that authentication should not be done without first configuring https.

2 Likes

This does indeed seems like a sensible enhancement (to me)... If you raise a PR please target it at the dev branch - and with 4.0 imminent then the sooner the better (imho) :slight_smile:

5 Likes
4 Likes

@knolleary, thank you for merging the pull request.

If anybody is interested in creating their own authentication system to replace the basic-auth that protects the "http in node" and dashboard and other nodes that provide http urls, let me know so we can open a new thread. I will share my work in progress so that we can collaborate and work out the details with the goal of hardening the auth.

6 Likes

Great work, Kevin -- I can definitely use this feature. One question: can this work with the httpAdmin routes, like /admin and other built-in apis? Or is that not configurable in settings.js?

1 Like

No, this only applies to the HTTP Node routes.

I suspected so... but was also interested in whether there was any technical reason why it could NOT be applied to httpAdmin routes? I mean other than it's not coded that way yet. Could the editor, flow, comms, etc. still work correctly with additional middleware in place?

This is because there are 2 ExpressJS instances used by Node-RED, one for admin use and one for user-facing use. Each, of course, therefore needs its own middleware. Technically (from an ExpressJS/Node.js perspective at least) there is nothing stopping a similar approach to be used for the admin web server. But it would be (and indeed should be) separate from the user-facing version.

Yep, that's what I was looking for -- so the same technique could potentially be configured in a separate section of the settings.js and applied to the admin express instance? If the community found it useful, of course, and the core team did not see any potential issues with it...

1 Like

While you could add extra middleware to protect the admin routes, such as some middleware that detects multiple failed login attempts and moves that ip to a blocked list, I would definitely not try to replace the built-in admin authentication system. And for testing purposes, I did try just now to use my auth system as middleware to protect the admin http routes and it was successful. BUT, it would not be able to secure the websocket comms and that would leave you less secure than the built-in auth.

The ip blocker middleware I reference is what lead me to working on my httpNode auth. I simply wanted to have my admin ip blocker middleware also work to protect the httpNode but realized that the built-in basic auth wasnt flexible enough to allow it. And then of course I went off the deep end...

2 Likes