Advice neededa; Editing / Keeping multiple secrets

I just published my latest update to my DDNS node for Cloudflare.

In it I split IP acquisition and DNS update into (optional) two nodes to fit my use case.
To ensure that a spoke only can update its own DNS entry it needs to submit a password.
The hub checks it.
On the spoke it is a simple credential, on the Hub I currently have a JSON object with keys for host and values as passwords. It's an ugly hack and can't stay like that.

I was thinking of an editable list to capture host/password pairs and then create 2 arrays (later stringify): one for the hosts a property and one for the passwords aas credentials.

Now the questions:

  • is that a sensible approach or is there a better way?
  • how can I access credentials in oneditprepare to build the editable list?

Anything that stores passwords is not secure and can never be. I don't think storing as a credential really isn't any better as they only hide stuff really I think. I don't believe they actually make it secure (unless you have a way to prevent people with editor access from accessing the settings.js file but then Node-RED itself probably couldn't either).

The "problem" with Node-RED is that, being a general-purpose dev platform, it has a lot of access. So I think that the only possibility is to have an external service that Node-RED cannot directly access, only via an API. Captured passwords must be pre-hashed (maybe at the client), and then sent to the external service where they probably need to be re-hashed.

But inventing such a service is fraught with issues - use a proper key-store instead.

Sorry, have to rush. Catch up later.

Thx for the rant. AFAIK credentials are stored encrypted, so access to settings.js won’t provide you access.

Anyone who has access to OS level of a running application can wreck it. Point is case: common practice in containers (unrelated to NodeRED) is to use env variables for credentials. So messing with the KeyValue store is easy Even Docker secrets are just a cat away from disclosure. Once you have access to kubectl all bets are off.

I don’t see NodeRED being worse. I’d appreciate constructive discussion.

Correct

You could use the editableList widget and store the array in a credentials setting.

Or if you want the host names not encrypted, you could split out the hostnames and passwords into separate arrays but then you need some way to key them together (or always ensure the entries are synced)

as onedtprepare runs client side it has to request/get things from the server side - but you should not pass actual credentials to the client side. What we normally do is pass "password" instead - so that if it is editied/changed we can then send back the new value - but do not expose the original.

1 Like

Had to rush the post as headed out with the family. Now have only mobile.

Needs more thought. You can't get the original password text but you DO get access to the hash in settings. This is not good I don't think. Enough for casual protection but not for anything really valuable I'm fairly sure. A node-red instance with write access to settings could also change the hash to something known maybe?

This is why keystores exist. Rule 1: don't use the same system for security and general processing.

PS: You will know when I'm ranting. This is certainly not that. Do whatever you want, just don't pass things off as Secure unless prosperity tested. You asked, I responded.

Is there an annotated example for editable list? All the "usual" input fields get bound to input while the list (unsurprisingly) gets bound to ol. How to populate / collect the values?

Slightly tricky. I would need to alter each password isn't it. The value is just a string even if you could parse it into a JS Object.

It's fairly well documented (in the link I wrote above). You don't need anything bound - you can populate your array in oneditprepare and then grab the user input in oneditsave and set your array.

There are also a fair few nodes you can look at for additional clues. Like the inject node:

2 Likes

Hi @Stwissel

The editable list is a little daunting at first, but once you get it - it picks up quickly
Here is a minimal guide

  1. Define your config value for the list
defaults: {
    filters: { value: [] }, /* this will be an array of objects) /*
    ...
},
  1. Define your control (don't bind it to config value name)
<div>
    <ol id="myFilters"> </ol>
</div>
  1. on oneditprepare, set it up + restore previous values.
$('#myFilters').editableList({
   removable: true,
   addButton: 'Add New Item',
   addItem: AddItem
});

/*  Restore items - this calls the addItem assignment for each object in your array */
this.filters.forEach((Item) => {$('#myFilters').editableList('addItem', Item)});
  1. Create the addItem callback
function AddItem(container, index, data) {
 /* data      : Will be the element in the array, its empty when the button is clicked to add 
  *             Construct an object of your choosing 
  * container : Is the Dom element that is added to the list                                  
  *             you can bind values to your html elements as per normal javascript
                You are responsible   for adding html content to it
  * index     : Is the item index in the list     
  */

   // Add the item data to the container
   $(container).data('data', data);
}
  1. on oneditsave write the list data to your config
const Items = $('#myFilters').editableList('items')
this.filters = [];
for (let i = 0; i < Items.length; i++) {
    const ItemData = Items[i].data('data');
    this.filters.push(ItemData)
}

I think I have that right - check my example here.

You beat me to it @Steve-Mcl :smile:

1 Like

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.