默认情况下,Node-RED编辑器没有安全保护 - 任何能够访问其IP地址的人都可以进入编辑器并部署更改。
这仅适用于在受信任的网络上运行的情况。
本指南介绍如何保护Node-RED的安全。安全防护分为三个部分:
要启用通过HTTPS而非默认HTTP访问Node-RED编辑器,您可以在设置文件中使用https配置选项。
https选项可以是一组静态配置参数,或者从Node-RED 1.1.0版本开始,也可以是一个返回配置参数的函数。
完整选项集在此处有文档说明。
至少,选项应包括:
key - PEM格式的私钥,以String或Buffer形式提供cert - PEM格式的证书链,提供为String或Buffer默认的Node-RED设置文件中包含一个被注释掉的https部分,可用于从本地文件加载证书。
https: {
key: require("fs").readFileSync('privkey.pem'),
cert: require("fs").readFileSync('cert.pem')
},
自 Node-RED 1.1.0 起
如果https属性是一个函数,它可以用来返回选项对象。
该函数可以选择返回一个Promise,该Promise将解析为选项对象,
允许它异步完成。
https: function() {
return new Promise((resolve, reject) => {
var key, cert;
// Do some work to obtain valid certificates
// ...
resolve({
key: key
cert: cert
})
});
}
自 Node-RED 1.1.0 起
可以配置Node-RED使其定期刷新HTTPS证书而无需重启Node-RED。具体操作如下:
https 设置 必须 是一个可调用的函数,用于获取更新的证书httpsRefreshInterval设置为Node-RED调用https函数获取更新详情的频率(以小时为单位)。https 函数应判断当前证书是否会在接下来的 httpsRefreshInterval 周期内过期,如果是,则生成一组新证书。如果不需要更新,该函数可以返回 undefined 或 null。
编辑器和Admin API支持两种类型的身份验证:
要在编辑器和Admin API上启用用户身份验证,请取消设置文件中adminAuth属性的注释:
adminAuth: {
type: "credentials",
users: [
{
username: "admin",
password: "$2a$08$zZWtXTja0fB1pzD4sHCMyOCMYz2Z6dNbM6tl8sJogENOMcxWV9DN.",
permissions: "*"
},
{
username: "george",
password: "$2b$08$wuAqPiKJlVN27eF5qJp.RuQYuy6ZYONW7a/UWYxDTtwKFCdB8F19y",
permissions: "read"
}
]
}
users属性是一个用户对象数组。这允许您定义多个用户,每个用户都可以拥有不同的权限。
上面的示例配置定义了两个用户。一个名为admin的用户拥有编辑器的全部权限,密码为password。另一个名为george的用户被授予只读访问权限。
请注意,密码已使用bcrypt算法进行安全哈希处理。
httpAdminAuth
could be used to enable HTTP Basic Authentication on the editor. This option is
deprecated and should not be used.
如果您使用的是Node-RED 1.1.0或更高版本,可以使用以下命令:
node-red admin hash-pw
对于旧版本的Node-RED,您可以:
安装独立的node-red-admin命令行工具并使用以下命令:
node-red-admin hash-pw
或者,找到Node-RED的安装目录并使用以下命令:
node -e "console.log(require('bcryptjs').hashSync(process.argv[1], 8));" your-password-here
在所有情况下,您都将获得密码的哈希版本,然后可以将其粘贴到您的设置文件中。
要使用外部认证源,Node-RED可以利用Passport提供的多种策略。
Node-RED 提供了针对 Twitter 和 GitHub 的认证模块。这些模块封装了特定策略的一些细节,使其更易于使用。同时它们也可以作为模板,用于其他类似策略的认证。
以下示例展示了如何配置以在不使用我们提供的auth模块的情况下对Twitter进行身份验证。
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: ["*"]}
]
}
strategy 属性支持以下选项:
name - 正在使用的passport策略名称strategy - passport策略模块label/icon - 用于登录页面。icon可以是任何FontAwesome图标名称。options - 创建passport策略时传入的配置对象。具体所需参数请参考该策略自身的文档。关于callbackURL和callbackMethod的说明请见下文。verify - 策略使用的验证函数。如果用户有效,它必须调用done并将用户资料作为第二个参数传入。该用户资料预期包含一个username属性,用于核对有效用户列表。Passport尝试标准化用户资料对象,因此大多数策略都会提供此属性。autoLogin - 布尔值,当设为true时会自动重定向到认证提供方,而不是要求用户点击按钮。策略使用的callbackURL是认证提供者在认证尝试后将重定向到的地址。它必须是您的Node-RED编辑器URL,并在路径后添加/auth/strategy/callback。例如,如果您通过http://localhost:1880访问编辑器,则应使用http://localhost:1880/auth/strategy/callback。
默认情况下,callbackURL会监听GET请求。如需改用POST请求,请将callbackMethod设置为POST。
上述示例配置将阻止任何人访问编辑器,除非他们登录。
在某些情况下,可能需要允许所有人拥有一定程度的访问权限。
通常,这指的是赋予编辑器只读访问权限。为此,
可以在adminAuth设置中添加default属性来定义
默认用户:
adminAuth: {
type: "credentials",
users: [ /* list of users */ ],
default: {
permissions: "read"
}
}
在Node-RED 0.14版本之前,用户可能拥有以下两种权限之一:
* - 完全访问权限read - 只读访问权限从Node-RED 0.14版本开始,权限可以更加细化,为了支持这一点,该属性可以像以前一样是单个字符串,也可以是包含多个权限的数组。
Admin API的每个方法都定义了访问所需的权限级别。
该权限模型基于资源。例如,要获取当前流配置,
用户需要具备flows.read权限。但要更新流配置则需要
flows.write权限。
默认情况下,访问令牌在创建7天后会过期。我们目前不支持通过刷新令牌来延长有效期。
过期时间可以通过设置adminAuth配置中的sessionExpiryTime属性来自定义。该属性以秒为单位定义令牌的有效期。例如,要将令牌设置为1天后过期:
adminAuth: {
sessionExpiryTime: 86400,
...
}
设置adminAuth属性后,Admin API文档描述了如何访问该API。
与其在设置文件中硬编码用户信息,也可以插入自定义代码来验证用户身份。这使得与现有认证方案的集成成为可能。
以下示例展示了如何使用外部模块来提供自定义身份验证代码。
/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属性以加载此模块:adminAuth: require("./user-authentication")
自 Node-RED 1.1.0 起
在某些情况下,您可能需要使用自己的身份验证令牌,而不使用Node-RED生成的令牌。例如:
adminAuth设置可以包含一个tokens函数。当向admin api发出的请求不包含Node-RED可识别的认证令牌时,将调用此函数。该函数会接收请求中提供的令牌,并应返回一个Promise,解析结果为已认证用户或null(若令牌无效)。
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);
}
});
},
...
}
默认情况下,它将使用Authorization HTTP头部并期望一个Bearer类型的令牌 - 仅将令牌值传递给函数。如果不是Bearer类型的令牌,则会将包含类型和值的完整Authorization头部值传递给函数。
要使用不同的HTTP头部,可以通过tokenHeader设置来指定使用哪个头部:
adminAuth: {
...
tokens: function(token) {
...
},
tokenHeader: "x-my-custom-token"
}
要在不显示登录提示的情况下使用自定义令牌访问编辑器,请在URL中添加?access_token=。编辑器将在本地存储该令牌,并在所有后续请求中使用它。
HTTP In节点暴露的路由可以通过基本身份验证进行安全保护。
settings.js文件中的httpNodeAuth属性可用于定义允许访问路由的单一用户名和密码。
httpNodeAuth: {user:"user",pass:"$2a$08$zZWtXTja0fB1pzD4sHCMyOCMYz2Z6dNbM6tl8sJogENOMcxWV9DN."},
pass属性使用与adminAuth相同的格式。更多信息请参阅生成密码哈希。
通过httpStatic属性定义的任何静态内容访问权限都可以使用httpStaticAuth属性进行保护,后者采用相同的格式。
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.
可以提供一个自定义的HTTP中间件,它将被添加到所有HTTP In节点之前,并且从Node-RED 1.1.0版本开始,也会添加到所有管理/编辑器路由之前。
对于HTTP In节点,中间件是通过httpNodeMiddleware设置提供的。
以下设置是一个限制http-in节点中HTTP访问速率的示例。
// 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
})
}
通过此配置,Node-RED进程可以避免内存耗尽,即使从http-in节点开始的流程需要较长时间处理。 当达到限制时,端点将返回默认消息"请求过多,请稍后再试"。
对于管理员/编辑路由,中间件通过httpAdminMiddleware设置提供。
例如,以下中间件可用于在所有管理员/编辑请求上设置X-Frame-Options HTTP头部。这可用于控制编辑器如何嵌入到其他页面中。
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();
},
其他可能的用途包括为路由添加额外的安全层或请求验证。
Node-RED: 面向事件驱动应用的低代码编程平台。
版权所有 OpenJS基金会 及 Node-RED 贡献者。保留所有权利。OpenJS基金会 拥有注册商标并使用商标。有关 OpenJS基金会 的商标列表,请参阅我们的 商标政策 和 商标列表。未在 OpenJS基金会商标列表 中标注的商标™或注册®商标归其各自持有人所有。使用这些商标并不意味着与它们有任何关联或获得其认可。
The OpenJS Foundation | 使用条款 | 隐私政策 | OpenJS基金会章程 | 商标政策 | 商标列表 | Cookie政策