By default, the Node-RED editor is not secured - anyone who can access its IP address can access the editor and deploy changes.
This is only suitable if you are running on a trusted network.
This guide describes how you can secure Node-RED. The security is split into three parts:
To enable access to the Node-RED Editor over HTTPS, rather than the default HTTP,
you can use the https
configuration option in your settings file.
The https
option can be either a static set of configuration options, or, since
Node-RED 1.1.0, a function that returns the options.
The full set of options are documented here.
As a minimum, the options should include:
key
- Private key in PEM format, provided as a String
or Buffer
cert
- Cert chain in PEM format, provided as a String
or Buffer
The default Node-RED settings file includes a commented out https
section that
can be used to load the certificates from local files.
https: {
key: require("fs").readFileSync('privkey.pem'),
cert: require("fs").readFileSync('cert.pem')
},
Since Node-RED 1.1.0
If the https
property is a function, it can be used to return the options object.
The function can optionally return a Promise that will resolve to the options object,
allowing it to complete asynchronously.
https: function() {
return new Promise((resolve, reject) => {
var key, cert;
// Do some work to obtain valid certificates
// ...
resolve({
key: key
cert: cert
})
});
}
Since Node-RED 1.1.0
It is possible to configure Node-RED to periodically refresh its HTTPS certificates without having to restart Node-RED. To do this:
https
setting must be a Function that can be called to get the updated certificateshttpsRefreshInterval
to how often (in hours) Node-RED should call the https
function
to get updated details.The https
function should determine if the current certificates will expire within the next
httpsRefreshInterval
period, and if so, generate a new set of certificates. If no update
is required, the function can return undefined
or null
.
The Editor and Admin API supports two types of authentication:
To enable user authentication on the Editor and Admin API, uncomment the adminAuth
property in your settings file:
adminAuth: {
type: "credentials",
users: [
{
username: "admin",
password: "$2a$08$zZWtXTja0fB1pzD4sHCMyOCMYz2Z6dNbM6tl8sJogENOMcxWV9DN.",
permissions: "*"
},
{
username: "george",
password: "$2b$08$wuAqPiKJlVN27eF5qJp.RuQYuy6ZYONW7a/UWYxDTtwKFCdB8F19y",
permissions: "read"
}
]
}
The users
property is an array of user objects. This allows you to define
multiple users, each of whom can have different permissions.
This example configuration above defines two users. One called admin
who has
permission to do everything within the editor and has a password of password
.
The other called george
who is given read-only access.
Note that the passwords are securely hashed using the bcrypt algorithm.
httpAdminAuth
could be used to enable HTTP Basic Authentication on the editor. This option is
deprecated and should not be used.
If you are using Node-RED 1.1.0 or later, you can use the command:
node-red admin hash-pw
For older versions of Node-RED, you can either:
Install the separate node-red-admin
command-line tool and use the command:
node-red-admin hash-pw
Or, locate the directory Node-RED has been installed to and use the command:
node -e "console.log(require('bcryptjs').hashSync(process.argv[1], 8));" your-password-here
In all cases, you will get back the hashed version of your password which you can then paste into your settings file.
To use an external authentication source, Node-RED can take use a wide range of the strategies provided by Passport.
Node-RED authentication modules are available for both Twitter and GitHub. They wrap up some of the strategy-specific detail to make it easier to use. But they can also be used as a template for authenticating with other similar strategies.
The following example shows how to configure to authenticate against Twitter without using the auth module we provide.
adminAuth: {
type:"strategy",
strategy: {
name: "twitter",
label: 'Sign in with Twitter',
icon:"fa-twitter",
strategy: require("passport-twitter").Strategy,
options: {
consumerKey: TWITTER_APP_CONSUMER_KEY,
consumerSecret: TWITTER_APP_CONSUMER_SECRET,
callbackURL: "http://example.com/auth/strategy/callback",
verify: function(token, tokenSecret, profile, done) {
done(null, profile);
}
},
},
users: [
{ username: "knolleary",permissions: ["*"]}
]
}
The strategy
property takes the following options:
name
- the name of the passport strategy being usedstrategy
- the passport strategy modulelabel
/icon
- used on the login page. icon
can be any FontAwesome icon name.options
- an options object passed to the passport strategy when it is created.
Refer to the strategy’s own documentation for what it requires. See below for a
note on the callbackURL
and callbackMethod
.verify
- the verify function used by the strategy. It must call done
with
a user profile as the second argument if the user is valid. This is expected
to have a username
property that is used to check against the list of valid
users. Passport attempts to standardize the user profile object, so most strategies
provide this property.The callbackURL
used by a strategy is where the authentication provider will
redirect to following an auth attempt. It must be the URL of your Node-RED editor
with /auth/strategy/callback
added to the path. For example, if you access the
editor at http://localhost:1880
, you would use http://localhost:1880/auth/strategy/callback
.
By default, the callbackURL
will listen for GET
requests. To use POST
requests
instead, set callbackMethod
to POST
.
The example configuration above will prevent anyone from accessing the editor unless they log in.
In some cases, it is desirable to allow everyone some level of access.
Typically, this will be giving read-only access to the editor. To do this,
the default
property can be added to the adminAuth
setting to define
the default user:
adminAuth: {
type: "credentials",
users: [ /* list of users */ ],
default: {
permissions: "read"
}
}
Prior to Node-RED 0.14, users could have one of two permissions:
*
- full accessread
- read-only accessFrom Node-RED 0.14 the permissions can be much finer grained and to support that, the property can either be a single string as before, or an array containing multiple permissions.
Each method of the Admin API defines what permission level is needed to access it.
The permission model is resource based. For example, to get the current flow configuration,
a user will require the flows.read
permission. But to update the flows they will require
the flows.write
permission.
By default, access tokens expire after 7 days after they are created. We do not currently support refreshing the token to extend this period.
The expiration time can be customised by setting the sessionExpiryTime
property
of the adminAuth
setting. This defines, in seconds, how long a token is valid
for. For example, to set the tokens to expire after 1 day:
adminAuth: {
sessionExpiryTime: 86400,
...
}
With the adminAuth
property set, the Admin API documentation
describes how to access the API.
Rather than hardcode users into the settings file, it is also possible to plug in custom code to authenticate users. This makes it possible to integrate with existing authentication schemes.
The following example shows how an external module can be used to provide the custom authentication code.
<node-red>/user-authentication.js
module.exports = {
type: "credentials",
users: function(username) {
return new Promise(function(resolve) {
// Do whatever work is needed to check username is a valid
// user.
if (valid) {
// Resolve with the user object. It must contain
// properties 'username' and 'permissions'
var user = { username: "admin", permissions: "*" };
resolve(user);
} else {
// Resolve with null to indicate this user does not exist
resolve(null);
}
});
},
authenticate: function(username,password) {
return new Promise(function(resolve) {
// Do whatever work is needed to validate the username/password
// combination.
if (valid) {
// Resolve with the user object. Equivalent to having
// called users(username);
var user = { username: "admin", permissions: "*" };
resolve(user);
} else {
// Resolve with null to indicate the username/password pair
// were not valid.
resolve(null);
}
});
},
default: function() {
return new Promise(function(resolve) {
// Resolve with the user object for the default user.
// If no default user exists, resolve with null.
resolve({anonymous: true, permissions:"read"});
});
}
}
adminAuth
property in settings.js to load this module:adminAuth: require("./user-authentication")
Since Node-RED 1.1.0
In some circumstances you may need to use your own authentication tokens and not use those generated by Node-RED. For example:
The adminAuth
setting can include a tokens
function. This function will be called
if a request to the admin api does not contain an authentication token that Node-RED
recognises as one of its own. It is passed the token provided in the request and should
return a Promise that resolves with either the authenticated user, or null
if the
token is not valid.
adminAuth: {
...
tokens: function(token) {
return new Promise(function(resolve, reject) {
// Do whatever work is needed to check token is valid
if (valid) {
// Resolve with the user object. It must contain
// properties 'username' and 'permissions'
var user = { username: 'admin', permissions: '*' };
resolve(user);
} else {
// Resolve with null as this user does not exist
resolve(null);
}
});
},
...
}
By default, it will use the Authorization
http header and expect a Bearer
type
token - passing in just the value of the token to the function. If it is not a
Bearer
type token, then the full value of the Authorization
header will be
passed to the function, containing both type and value.
To use a different HTTP header, the tokenHeader
setting can be used to identify
which header to use:
adminAuth: {
...
tokens: function(token) {
...
},
tokenHeader: "x-my-custom-token"
}
To access the editor using a custom token without the login prompt, add ?access_token=<ACCESS_TOKEN>
to the URL. The editor will store that token locally and use it for all future requests.
The routes exposed by the HTTP In nodes can be secured using basic authentication.
The httpNodeAuth
property in your settings.js
file can be used to define a single
username and password that will be allowed to access the routes.
httpNodeAuth: {user:"user",pass:"$2a$08$zZWtXTja0fB1pzD4sHCMyOCMYz2Z6dNbM6tl8sJogENOMcxWV9DN."},
The pass
property uses the same format as adminAuth
. See Generating the password hash for more information.
Access to any static content defined by the httpStatic
property can be secured
using the httpStaticAuth
property, which uses the same format.
pass
property
was expected to be an MD5 hash. This is cryptographically insecure, so has been
superseded with bcrypt, as used by adminAuth
. For backwards compatibility, MD5
hashes are still supported - but they are not recommended.
It is possible to provide custom HTTP middleware that will be added in front of
all HTTP In
nodes and, since Node-RED 1.1.0, in front of all admin/editor routes.
For the HTTP In
nodes, the middleware is provided as the httpNodeMiddleware
setting.
The following setting is an example to limit the HTTP access rate in http-in nodes.
// Run `npm install express-rate-limit` on `~/.node-red/` directory in advance
var rateLimit = require("express-rate-limit");
module.exports = {
httpNodeMiddleware: rateLimit({
windowMs: 1000, // 1000 milliseconds is set as the window time.
max: 10 // limit access rate to 10 requests/second
})
}
Using this configuration, the Node-RED process can avoid memory exhaustions even if the flows which start with the http-in node take time to process. When reaching the limitation, the endpoints will return the default message, “Too many requests, please try again later.”.
For the admin/editor routes, the middleware is provided as the httpAdminMiddleware
setting.
For example, the following middleware could be used to set the X-Frame-Options
http header
on all admin/editor requests. This can be used to control how the editor is embedded on
other pages.
httpAdminMiddleware: function(req, res, next) {
// Set the X-Frame-Options header to limit where the editor
// can be embedded
res.set('X-Frame-Options', 'sameorigin');
next();
},
Other possible uses would be to add additional layers of security or request verification to the routes.
Node-RED: Low-code programming for event-driven applications.
Copyright OpenJS Foundation and Node-RED contributors. All rights reserved. The OpenJS Foundation has registered trademarks and uses trademarks. For a list of trademarks of the OpenJS Foundation, please see our Trademark Policy and Trademark List. Trademarks and logos not indicated on the list of OpenJS Foundation trademarks are trademarks™ or registered® trademarks of their respective holders. Use of them does not imply any affiliation with or endorsement by them.
The OpenJS Foundation | Terms of Use | Privacy Policy | OpenJS Foundation Bylaws | Trademark Policy | Trademark List | Cookie Policy