Node-Red Login Prompt

Securing Node-Red

UPDATE 10-01-2017:
a) The method for generating the password hash has been updated to use the new node-red-admin tool, which is more secure in that it does not use MD5 and does not require entering the password in plain text.
b) Securing HTTP interfaces exposed by nodes and static pages is described in a new section of the article.

This is the fourth and so far last installment of my article series on setting up and IoT base station using Raspberry PI, Node-Red and EmonCMS. In this article I will describe how to secure Node-Red to achieve a more secure IoT setup. If you have not already visited my other articles in this series, I recommend that you start off by visiting the first article, which also contains a brief introduction to the series.

In its default state, Node-Red is not secured in any way – it doesn’t even have user login – and is running on its default port, thus making it vulnerable for potential attacks targeted at Node-Red installations. Therefore, it is a brilliant idea to add some layers of security to the installation by enabling login and SSL, and reconfiguring Node-Red to use a different port.

Setting up login

The first natural step of securing a web application is by enabling user login. This is one of the most fundamental security measures for a web application and is one of the easiest, both in terms of setup and use.

To add login to Node-Red an additional package is required for the underlying Node installation to encrypt the stored passwords of the user accounts. To do so, simply install the bcryptjs node-red-admin packages using the Node package manager:

cd /usr/local/lib/
sudo npm install -g --unsafe-perm bcryptjs node-red-admin

Once installed, a password can be generated for the user we want to add, by running the following commands and entering the desired password for the user:

cd /usr/local/lib/node_modules
node-red-admin hash-pw

Now that we have a password hash for the user, user authentication can be enabled in Node-Red and the new user can be added. To do so, edit the Node-Red configuration file /usr/local/lib/node_modules/node-red/settings.js and add the following lines to the configuration. Substitute <username> with the desired username and <password_hash> with the one generated above:

    adminAuth: {
        type: "credentials",
        users: [{
            username: "<username>",
            password: "<password_hash>",
            permissions: "*"
        }]
    },

The above user profile will have full permissions, thus being able to edit (and delete) flows.

When enabling user authentication, Node-Red writes a sessions.json file to ~/.node-red of the user used to run the Node-Red process (the pi user by default). When running Node-Red from the low-write EmonBase image, this folder will not be writable and Node-Red will fail to respond completely.

One solution to this problem is to move the sessions file to a location that is always writable, such as /var/run/var /run/nodered and make a symbolic link to that from the local Node-Red folder. This can be easily achieved by running the following commands:

cd ~/.node-red
rpi-rw
sudo mkdir /var/run/nodered
test -e .sessions.json || touch .sessions.json
sudo cp .sessions.json /var/run/nodered
sudo chown -R pi:pi /var/run/nodered
mv .sessions.json .sessions.json_bak
sudo ln -s /var/run/nodered/.sessions.json .sessions.json

Changing the default port

Another quite natural step, in securing a web application is making sure that it does not respond to its default port – especially if it is exposed to the Internet. Malicious bots that targets a specific application will know its default port and look for installations that have not been reconfigured and try to attack those.

Fortunately, the port Node-Red is running on can be easily changed through the Node-Red configuration file. Edit the configuration file and change the line specifying the port number under module.exports:

uiPort: <port_number>,

Once done, save the file and restart Node-Red.

sudo service nodered restart

When changing the default port, remember to allow traffic on the new port through the firewall:

sudo ufw allow

Also, if you previously allowed traffic on the old port through the firewall, remember toturn that off again:

sudo ufw deny

Enabling SSL

Another security measure, which is designed to protect the visitor of a web application, is SSL – that is encrypting the communication between the user’s browser and the web application. This ensures that the information – possibly sensitive – sent between the user’s browser and the web application cannot be easily intercepted by third parties, e.g. through a man in the middle attack.

To further secure the Node-Red installation it should only be possible to access Node-Red over HTTPS, which will ensure that all communication between the user’s browser and Node-Red is encrypted. For this, a server certificate is required.

If you already have a server certificate installed in your Raspberry PI’s Apache installation you can continue to the next step, otherwise I recommend following the relevant steps in my article about securing EmonCMS.

Once the server certificates are in place Node-Red can be configured to serve them by, once again, editing the Node-Red settings.js configuration file, adding the paths of the server certificate key and certificate files:

https: {
    key: fs.readFileSync('<path_to_server_key>'),
    cert: fs.readFileSync('<path_to_server_cert>')
},

A last thing that is required for this to work is to uncomment the first line (remove the # at the beginning of the line), requiring the fs module.

Finally, restart Node-Red for the changes to take effect:

sudo service nodered restart

 Securing HTTP-based interfaces

One problem with the security of Node-Red has been with securing the interfaces exposed by nodes and static content. Nodes, like the rather popular node-contrib-node-ui, which exposes a dashboard-like user interface in a sub-path of the Node-Red administration interface, are inherently insecure.

This is because they are not considered as part of the administration interface and thus have no access to the administration interface’s security setup. This makes sense because they are user interfaces and not administrator interfaces. These interfaces use plain HTTP and at the moment no measures for turning on SSL for them exist.

As an alternative, it is possible to enable username/password protection using BasicAuth. This must be done separately for interfaces exposed by nodes and interfaces exposed by static content in the Node-Red web folders, as described in the Node-Red installation guide.

Simply uncomment the httpNodeAuth and httpStaticAuth directives in the settings.js file and update the username to your preference. Protected access can be enabled only for one user.

Replace the password hash with a new one generated using the node-red-admin tool:

node-red-admin hash-pw

When done, restart Node-Red:

sudo service nodered restart

Once restarted all exposed interfaces should require username and password to access.

Conclusion

Starting out with a Node-Red installation that lacks the most basic security measures, a few rather simple operations quickly strengthens the security of Node-Red significantly.

The end result is a Node-Red installation that is secure in terms of server authentication, which ensures the user that it has access to the correct server; and enables user level authentication to only allow access to known users.

Moving forward, adding additional security based on either private key or two-step authentication are welcome means of strengthening the user level authentication.

11 comments on “Securing Node-RedAdd yours →

  1. Thank you for your good article. I followed your steps to create the login for Node-Red. After I input “sudo service nodered restart” command. There is a login screen and I can use the generated password to access and deploy the flows. The UI dashboard is still accessible without password as expected. This is what I really want to have for Node-Red. It seems to be fine. But when I reboot my Pi. I cannot login to the Node-Red with the same password.

    Here is the error message – Potentially unhandled rejection [2] Error: ENOENT: no such file or directory, open ‘/home/pi/.node-red/.sessions.json’

    The symbolic link of .sessions.json file to the “/var/run/nodered” directory is missing. I found that there is no “/nodered” directory after reboot. I tried a couple times. The error message is the same. Could you advise if I did anything wrong? BTW, on my Pi , I cannot find “rpi-rw” command. So when I followed your procedures. It is only one command that I have to skip, not sure if this causes the problem.

    For now, I have to restore the .settings.js to original one and access the Node-Red without the login.

    1. Hi Attapon,

      Thank you for the kind words!

      Firstly, I am running Node-Red on a rather special Linux distribution (EmonCMS), which has a very limited number of write operations to the SD-card attached to the Raspberry PI. The rpi-r[o|w] commands toggles the read-only flag of the file system on and off.
      That you do not have those commands, you most probably have write access all of the time and need not worry about executing the commands.

      I do not have a good reason for why your .sessions.json file disappears upon reboot, but it might be that all entries in your /var/run folder that do not belong to a certain user or does not have certain permissions are automatically removed.
      Anyway, since you are running a Linux distribution with permanent write access to the file system, you should have no need for the symbolic link because Node-Red should be able to write to the sessions file in ~/.node-red/ just fine.
      So, I’d suggest that you simply try to delete the symbolic link and see if that does the trick.

      Let me know how it works out!

      Cheers!

      – Anders

  2. Hi Anders,

    Thanks for your prompt reply. Yes, the authentication for my Node-Red is now under control after removing the symbolic link per your suggestion. I probably worried too much for the password lock, then I added the extra procedures which are not related to my environment.

    It’s also good to know about EmonCMS from your explanation, thanks again.

    Cheers!
    Attapon L.

    1. Hi Buzatu,

      According to the official NodeRed documentation it is possible to define several users with different permissions.
      In this way you can define admin users with write permission and regular users with read-only permission, thus allowing them to only see the flows and the debug log. Since NodeRed 0.14 it is possible to define more fine-grained roles for users.

      Cheers!

      – Anders

  3. I haven’t yet tried to secure Node-RED, but I was interested in changing its port. This was not quite so straightforward as I had expected.

    Recent versions of the Beaglebone Black come with Node-RED installed. Modifying the Node-RED port on these units, which use systemd to initialize and monitor the system, requires more than just modifying the settings.js file. To change Node-RED’s port to, say, port 2468, do this (logged in as root or using sudo):

    Find /lib/systemd/system/node-red.socket and edit it so that
    ListenStream=2468

    Edit the original settings.js file (usually in BBB’s /root/.node-red/ directory) to read
    var port = process.env.LISTEN_PID > 0 ? ‘systemd’ : 2468;

    I.e., in both cases, simply change 1880 to 2468.

    Reboot the BBB. It now associates port 2468 with Node-RED. If you’ve set up port forwarding on your router, be sure to change it, too.

    Cheers,
    ThisEndUp

    1. Hi ThisEndUp,

      Thanks for your valuable comment!

      I guess much of what I write here for RPI works for BBB as well, although with system specific modifications, such as those you suggest for changing the port.

      I have no experience with BBB, but no doubt things work different on various systems.

      Cheers,
      Anders

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.

%d bloggers like this: