I have built some REST APIs with the node HTTP IN which are authorized using JWT. For the authorization I use a separate node until now. I would like to switch to a central check with the function httpNodeMiddleware.
Unfortunately the middleware applies either to all HTTP IN nodes, or to none. A specific disabling of the middleware in the HTTP IN node is not possible. Thus, I cannot provide generally accessible endpoints. I would like to change this and use the thread to discuss my idea with the community.
My suggestion would be to use a checkbox in the HTTP IN node to enable (default) or disable the middleware. The implementation would be possible with very little effort.
If you had an easy question, you would have gotten 20 responses.
I have thought about what you are trying to do and it has me curious. Does that mean that you are not using httpNodeAuth and that you have manually entered middleware in the settings.js file?
If that is the case, then why not remove the httpNodeMiddleware from settings.js and then call it in a function node handling the http in response? Or perhaps you can prefix your http in routes with /apibase/yourapi and then in the httpNodeMiddleware check the path.startsWith('/apibase') and call next() right away to skip the jwt checking?
@NetHans Whilst I can see the benefit of what you're proposing, I have some concerns.
In some installs, the admin may require the middleware to be applied to all routes and this would allow the flow author to bypass it. That could have very unintended side effects.
You can certainly achieve it today as @kevinGodell suggests without any changes to the nodes.
I would like to find a way to provide more flexible Auth options for the http routes, without having to resort to custom middleware. That's been on the backlog for some time and some of our recent work on FlowForge has reaffirmed the need for this. What shape that takes, I'm not sure at this point... but I digress from your original suggestion.
@kevinGodell, I do not use httpNodeAuth. Since the users that have access are dynamic and come from multiple user administrations. Primarily JsonWebTokens are used. But also MS Active Directory and a database serve as source for the access controllers of the HTTP-IN nodes. I check the authorization with several self-created nodes, which I grouped in a sub-flow. This means that after each HTTP-IN node this subflow must be called. I don't find this a nice solution. I would prefer to implement the authorization centrally and defined by the admin via the middleware. I agree with @knolleary that a switch to disable the middleware for authorization tasks is a security hole. But there are endpoints which do not require authorization. A combination of free and authorized endpoints is currently only possible via the middleware by defining paths in the middleware.
For me, the settings in settings.json are general definitions of how a Node-RED instance should work. Dynamic content should not be defined here as a comparison value. The paths of the HTTP-IN node can change or new ones can be added. But in such a case I don't want to have to adjust settings.json.
Currently a HTTP-IN node can only be identified by the path and the HTTP method. Node names or request data are unstable and unsuitable for identification.
What do you think about the suggestion that the middleware is made aware of the caller. This way the middleware can check if the call comes from an HTTP-IN node or not. In addition, I would suggest that the HTTP-IN nodes can be tagged, which can then be evaluated in the middleware. The tags could be defined as a list in the settings.json by the admin. This would create a flexibility which can be controlled by the admin. If the admin does not want to allow open endpoints, he does not provide appropriate tags and middleware.
I am aware that this suggestion is also not 100% safe, as users can provide sensitive endpoints openly if free middleware is available. However, it would be a compromise of both views. In addition, the admin always has the option of not offering open middleware in the first place.
It would also be worth considering whether the decision principle of httpNodeMiddleware should not be reversed. Currently, access is allowed after all middlewares have been passed through, if the opposite is not specified in any middleware. Safe would be safe if access is denied from the ground up and must be explicitly enabled in the middleware. To maintain the current state, this would require a default middleware to be defined in settings.json that allows all access. But this topic would lead too far here.
That sounds interesting. Except that isn't the middleware BEFORE the http-in? That would require it to be AFTER wouldn't it? Web endpoint security does normally happen before reaching the endpoint.
Perhaps another approach would be that all http-in nodes register their URL and METHOD in an external file (or via a Node-RED admin API). That way the middleware could query them and make appropriate decisions dynamically?
Another possible approach might be to provide a middleware capability that only acts on http-in nodes?
Either way, if you let Editors/flow-designers make decisions on which endpoints have security and which do not, you run a security risk.
Another approach might be a split one where you have some fixed, basic security that, for example, might ensure that only AUTHENTICATED users can even reach a node-red endpoint. Then a second level that provides the optional AUTHORISATION you are discussing.
It is up to individual node implementations to attach httpNodeMiddleware if it set. So typically it will only apply to the HTTP In nodes already. For example, node-red-dashboard has its own middleware option set via ui.middleware.
We want to find a way to provide more flexible auth options without requiring the user to manually edit any files. As soon as it requires editing files, it makes it much harder for hosted Node-RED environments to adopt. It is also much harder for users to achieve.
Not wanting to get bounced into designing it right now, but the rough shape I had in mind was a new HTTP Security config node used by the HTTP In nodes. That node would allow you to define the required security on the route. In what form that takes, I don't know as we haven't looked at it properly yet. But that's the general direction I see this going to provide the sort of capability users are asking for.
To help this for now, you can filter out the free api from the auth api with the simple prefix to the routes /noauth/api1 and /auth/api2, or something similar. Then, when later adding extra http in endpoints, just add them with the proper prefix.
Also, you can kinda sorta make the middleware dynamic. If the middleware reaches to some other file such as require('./my-list-of-free-api') and uses that for the checking. That list can be updated separately without ever having to go back and re-edit the settings file. This would require some other node that can also write to that list to be updated from the admin editor, but not very difficult. I do that with my middleware project that I am experimenting with.
Having node-red be more secure by default would be a bit tricky since many are accustomed to the way it is. Also, some hide their node-red behind proxies and never setup any type of security and let the proxy handle access.
I like the idea of a config node. I can envision it that it allows you to dynamically add a stack of 1 or more middleware functions (req, res, next) => {next()}. That config node containing the stack of middlewares could easily be used in other http in nodes and secure whatever route needed. If you open another discussion somewhere, I will add my 2 cents.
I'm all for making it easier to authenticate and authorise access. Of course, devil is in the detail with the danger being that of "security theatre" where people end up thinking they they are secure but they are not.
Anyway, I look forward to seeing the design notes.