-
-
Notifications
You must be signed in to change notification settings - Fork 86
Security Design v2
Update 2022-01-19: This page is outdated and kept only for historic reference. Please check out the more detailed information available in the Tech docs either here on GitHub pages or via the link in any uibuilder node.
This is a write-up of my latest proposal for securing user interfaces built with uibuilder and Node-RED. It is still subject to change and I'm happy to take feedback. Please use this forum post to discuss.
There is a separate code branch for the security build - boringly called the Security branch. You are welcome to try it out but please note that it may not always work as expected and will contain all sorts of weird debugging. I will update the forum when the code reaches beta quality.
- Should be as simple as possible to use - uibuilder itself should hide much of the complexity.
- Must be optional (not everyone requires UI security).
- Must be independent of Node-RED core security.
- Must allow for custom user validation. User data must be outside of uibuilder and outside of Node-RED for security.
- Must allow for custom session creation/validation/destruction.
- Must allow for timed session validity.
- Must warn if not using TLS. (If in production, should error out if not using TLS).
- Must provide security for websocket communications.
- Should avoid storing a token in browser storage (to reduce XSS and other hijack attacks).
- Should allow browser reload to stay logged in. If the token isn't stored in browser storage, that means that the server must be able to reauthorise the client. But it should only do that to the same IP address. It should probably also only do it within the short timeout (e.g. 30sec since the last ping from the client).
- Any "secrets" should be stored in the uibuilder node as a credential.
- Must allow for anonymous access.
- YOU are responsible for the security of your data, users and systems. Not me. Sorry. No guarantees or warranties are given or implied. Get your systems audited, tested and certified by professionals.
- There is no point using logins if you don't secure communications using TLS. If you try (for testing maybe?), you will get continual warnings in your Node-RED logs.
- Only you know how to validate whether someone is who they claim to be. I can't know that. So you have to write the code for that part. I will provide a simplistic and basic method as a starting point.
- Your UI should not include any sensitive data and therefore should not need a login before delivery of the core resources to a client.
- uibuilder will use websocket-based login, not HTTP(s) or an API. (I may create an API method at some point if enough people feel strongly enough about this).
- Websocket broadcasts and uibuilder control messages will be permitted (from server to clients) without authentication. uibuilder control messages will be permitted from the clients to the server without authentication.
- I will use JavaScript Web Tokens (JWT) to make life easier. However, JWT is NOT a security mechanism (amazing how many people get that wrong), it is a convenience mechanism. JWT is liable to session hijack and man-in-the-middle attacks. So token lifespan should be short and ongoing session validation is important.
-
Tokens should be cryptographically secure.JWT is not secure, the token is signed not encrypted. Anyone with the "secret" can read the token, that's how JWT is meant to work. To make this easy, uibuilder will take care of JWT for you. - uibuilder relies heavily on websocket communication. Unfortunately, ws does not support custom headers except on initial handshake so standard methods for session validation don't work. Therefore, uibuilder will provide a custom method.
- User & session validation will use a custom Node.js module (written by you though I will provide something basic as a starter), changes to the module will require reloading Node-RED. See bullet 2 above.
- Session management requires a session per client. A single user might have many clients open (multiple desktop browser tabs, mobile browser tabs, etc). So this can mount up. Be aware of resource utilisation.
- Session management requires a check for each client for each message sent/received. That's a LOT of checks, session checks need to be efficient and short.
- Session management will be memory based by default. Restarting Node-RED will invalidate all sessions. This may change.
Authentication checks will happen via a call to uibuilder.logon(userData)
from your front-end code. You may pass an object containing additional user information as the single parameter. At minimum, you need to pass some kind of identifier. Typically, you will also give a password.
That data will be collected from your user via a form typically, an internal variable tells you whether the current user is authenticated (uibuilder.get('isAuthorised')
). If they are authorised, another internal variable holds the token and a 3rd holds the token expiry date/time. The token will be passed back to the server every time the client sends a message so that it can be validated.
If the server receives an invalid token, it will invalidate the session (and may log the user out of all their sessions).
When the server receives a logon
control msg from a client, it will call a logon function which will reference your external module to validate the user information. Assuming the user data is valid, the external function either returns true
or an object with a defined schema (which allows you to return information back to the user such as messages to pay dues, reminders to change passwords, or anything else that you like).
Upon validation of the user, uibuilder will create a session entry for that connection/user. Sessions may (and should) have a timeout. Session creation, destruction and validation are also done by your external module. Session creation and optionally validation functions may return an object which will be folded into the JWT which uibuilder will create.
I've not quite worked out the best approaches for these as yet.
- It is yet possible that I'll hand over session management to a standard library. However, I suspect that none are flexible enough & not many properly handle websocket sessions.
- There may be a need for 2 levels of session validation? One that will refresh the token on a short time period (typically 30 seconds as this is how often your client will send a
ping
message to the server). The second will typically be on a longer time period that you will choose, typically a few days. - Invalid tokens received by the server might cause a user to be logged out of all their sessions?
- Perhaps I should use a timeout on the tokenExpiry information so that the data is cleared automatically rather than having to wait for the next message exchange.
- I should CERTAINLY add event's for logon/logout so that FE code can be more dynamic.
- Security (Boolean} will be optional via a setting for each uibuilder node instance.
- Session quick refresh {Boolean} will enable a refresh/quick validation function to be called for every 'packet' (e.g. any kind of message including
pings
which happen every 30 seconds). This helps reduce the risk of using JWT and ensures that sessions continue to get extended even if the user isn't interacting. - Session expiry {Number} will be controllable for each instance of the uibuilder node. This is the maximum session length. After this period, the session quick refresh will stop and the user must log in again (unless you do something clever on the front-end to resend details automatically - that has some risk of course in retaining sensitive data in the browser).
- User & session validation {Module} will use a custom Node.js module, changes to the module will require reloading Node-RED. This will support the use of a central module that will be found in
<uibRoot>/.config/security.js
or alternatively, in the instances root<uibRoot>/<url>/security.js
. This allows for different instances of uibuilder to have different authentication and session validation functions. A template example file will be provided in<uibRoot>/.config/security.js
that can be adjusted or replaced as needed.
Also see the original security design page.
Please feel free to add comments to the page (clearly mark with your initials & please add a commit msg so we know what has changed). You can contact me in the Discourse forum, or raise an issue here in GitHub! I will make sure all comments & suggestions are represented here.
-
Walkthrough 🔗 Getting started
-
In Progress and To Do 🔗 What's coming up for uibuilder?
-
Awesome uibuilder Examples, tutorials, templates and references.
-
How To
- How to send data when a client connects or reloads the page
- Send messages to a specific client
- Cache & Replay Messages
- Cache without a helper node
- Use webpack to optimise front-end libraries and code
- How to contribute & coding standards
- How to use NGINX as a proxy for Node-RED
- How to manage packages manually
- How to upload a file from the browser to Node-RED
-
Vanilla HTML/JavaScript examples
-
VueJS general hints, tips and examples
- Load Vue (v2 or v3) components without a build step (modern browsers only)
- How to use webpack with VueJS (or other frameworks)
- Awesome VueJS - Tips, info & libraries for working with Vue
- Components that work
-
VueJS v3 hints, tips and examples
-
VueJS v2 hints, tips and examples
- Dynamically load .vue files without a build step (Vue v2)
- Really Simple Example (Quote of the Day)
- Example charts using Chartkick, Chart.js, Google
- Example Gauge using vue-svg-gauge
- Example charts using ApexCharts
- Example chart using Vue-ECharts
- Example: debug messages using uibuilder & Vue
- Example: knob/gauge widget for uibuilder & Vue
- Example: Embedded video player using VideoJS
- Simple Button Acknowledgement Example Thanks to ringmybell
- Using Vue-Router without a build step Thanks to AFelix
- Vue Canvas Knob Component Thanks to Klaus Zerbe
-
Examples for other frameworks (check version before trying)
- Basic jQuery example - Updated for uibuilder v6.1
- ReactJS with no build - updated for uibuilder v5/6
-
Examples for other frameworks (may not work, out-of-date)
-
Outdated Pages (Historic only)
- v1 Examples (these need updating to uibuilder v2/v3/v4/v5)