默认情况下,Node-RED 编辑器没有安全保护——任何可以访问其 IP 地址的人都可以访问编辑器并部署更改。
这仅适用于在受信任的网络上运行的情况。
本指南描述了如何保护 Node-RED。安全性分为三个部分:
要启用通过 HTTPS 访问 Node-RED 编辑器,而不是默认的 HTTP,您可以在您的 设置文件 中使用 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;
// 做一些工作以获取有效证书
// ...
resolve({
key: key,
cert: cert
});
});
}
自 Node-RED 1.1.0 起
可以配置 Node-RED 定期刷新其 HTTPS 证书,而无需重启 Node-RED。要做到这一点:
https
设置 必须 是一个可以调用的函数以获取更新的证书httpsRefreshInterval
为 Node-RED 调用 https
函数以获取更新详情的频率(以小时为单位)。https
函数应确定当前证书是否将在下一个 httpsRefreshInterval
周期内过期,如果是,则生成一组新的证书。如果不需要更新,则函数可以返回 undefined
或 null
。
编辑器和管理 API 支持两种类型的身份验证:
要启用编辑器和管理 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
可用于启用编辑器上的 HTTP 基本身份验证。此选项已被弃用,不应使用。
如果您使用的是 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: '使用 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
- 使用的护照策略名称strategy
- 护照策略模块label
/icon
- 用于登录页面。icon
可以是任何 FontAwesome 图标名称。options
- 传递给创建时护照策略的选项对象。请参考策略自己的文档以了解它所需的内容。请参见下面有关 callbackURL
和 callbackMethod
的说明。verify
- 策略所使用的验证函数。如果用户有效,它必须以用户配置文件作为第二个参数调用 done
。预计该配置文件具有用于检查有效用户列表的 username
属性。护照尝试标准化用户配置文件对象,因此大多数策略提供此属性。autoLogin
- 布尔值,当为 true
时,将自动重定向到身份验证提供者,而不是要求用户单击按钮。策略使用的 callbackURL
是身份验证提供者在进行身份验证尝试后重定向的地方。它必须是您的 Node-RED 编辑器 URL,并在路径中添加 /auth/strategy/callback
。例如,如果您在 http://localhost:1880
访问编辑器,则应使用 http://localhost:1880/auth/strategy/callback
。
默认情况下,callbackURL
将监听 GET
请求。要改为使用 POST
请求,请将 callbackMethod
设置为 POST
。
上述示例配置将阻止任何人访问编辑器,除非他们登录。
在某些情况下,希望允许每个人获得一定级别的访问权限。通常,这将是给予编辑器的只读访问权限。为此,可以将 default
属性添加到 adminAuth
设置,以定义默认用户:
adminAuth: {
type: "credentials",
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。
与其将用户硬编码到设置文件中,不如可以插入自定义代码来验证用户。这使得与现有身份验证方案集成成为可能。
以下示例展示了如何使用外部模块提供自定义身份验证代码。
<node-red>/user-authentication.js
的文件中。module.exports = {
type: "credentials",
users: function(username) {
return new Promise(function(resolve) {
// 执行所需的任何工作,以检查用户名是否有效用户。
if (valid) {
// 解析为用户对象。它必须包含 'username' 和 'permissions' 属性
var user = { username: "admin", permissions: "*" };
resolve(user);
} else {
// 解析为 null 以指示该用户不存在
resolve(null);
}
});
},
authenticate: function(username,password) {
return new Promise(function(resolve) {
// 执行所需的任何工作,以验证用户名/密码组合。
if (valid) {
// 解析为用户对象。相当于调用 users(username);
var user = { username: "admin", permissions: "*" };
resolve(user);
} else {
// 解析为 null 以指示用户名/密码对无效。
resolve(null);
}
});
},
default: function() {
return new Promise(function(resolve) {
// 解析为默认用户的用户对象。如果没有默认用户,则解析为 null。
resolve({anonymous: true, permissions:"read"});
});
}
}
adminAuth
属性以加载此模块:adminAuth: require("./user-authentication")
自 Node-RED 1.1.0 起
在某些情况下,您可能需要使用自己的身份验证令牌,而不是使用 Node-RED 生成的令牌。例如:
adminAuth
设置可以包含 tokens
函数。如果对管理 API 的请求不包含 Node-RED 识别为其自己的身份验证令牌,则将调用此函数。它传递请求中提供的令牌,并且应该返回一个 Promise,该 Promise 解析为经过身份验证的用户,否则为 null
(如果令牌无效)。
adminAuth: {
...
tokens: function(token) {
return new Promise(function(resolve, reject) {
// 执行所需的任何工作以检查令牌是否有效
if (valid) {
// 解析为用户对象。它必须包含 'username' 和 'permissions' 属性
var user = { username: 'admin', permissions: '*' };
resolve(user);
} else {
// 解析为 null,因为该用户不存在
resolve(null);
}
});
},
...
}
默认情况下,它将使用 Authorization
http 头并期望一个 Bearer
类型的令牌——仅将令牌的值传递给函数。如果不是 Bearer
类型的令牌,则将传递 Authorization
头的完整值,这将包含类型和值。
要使用不同的 HTTP 头,可以使用 tokenHeader
设置来确定使用哪个头:
adminAuth: {
...
tokens: function(token) {
...
},
tokenHeader: "x-my-custom-token"
}
要使用自定义令牌访问编辑器而不出现登录提示,请在 URL 中添加 ?access_token=<ACCESS_TOKEN>
。编辑器将本地存储该令牌,并在所有未来请求中使用它。
HTTP In 节点暴露的路由可以使用基本身份验证进行保护。
在您的 settings.js
文件中,可以使用 httpNodeAuth
属性定义允许访问这些路由的单个用户名和密码。
httpNodeAuth: {user:"user",pass:"$2a$08$zZWtXTja0fB1pzD4sHCMyOCMYz2Z6dNbM6tl8sJogENOMcxWV9DN."},
pass
属性使用与 adminAuth
相同的格式。有关更多信息,请参见 生成密码哈希。
使用 httpStatic
属性定义的任何静态内容的访问可以使用 httpStaticAuth
属性进行保护,格式相同。
pass
属性预期为 MD5 哈希。由于密码学不安全,因此已被 bcrypt 取代, bcrypt 由 adminAuth
使用。为了向后兼容,MD5 哈希仍受支持——但不推荐使用。
可以提供自定义 HTTP 中间件,它将添加到所有 HTTP In
节点前,自 Node-RED 1.1.0 起,添加到所有管理/编辑器路由前。
对于 HTTP In
节点,作为 httpNodeMiddleware
设置提供中间件。
以下设置是限制 HTTP In 节点中 HTTP 访问率的示例。
// 在 `~/.node-red/` 目录中提前运行 `npm install express-rate-limit`
var rateLimit = require("express-rate-limit");
module.exports = {
httpNodeMiddleware: rateLimit({
windowMs: 1000, // 设置窗口时间为 1000 毫秒。
max: 10 // 将访问速率限制为 10 个请求/秒
})
}
使用此配置,即使以 http-in 节点开头的流程需要一些处理时间,Node-RED 进程也可以避免内存耗尽。当达到限制时,端点将返回默认消息:“请求过多,请稍后再试。”
对于管理/编辑器路由,提供的中间件作为 httpAdminMiddleware
设置。
例如,以下中间件可用于在所有管理/编辑器请求上设置 X-Frame-Options
http 头。这可以用于控制编辑器如何嵌入到其他页面。
httpAdminMiddleware: function(req, res, next) {
// 设置 X-Frame-Options 头以限制编辑器的嵌入位置
res.set('X-Frame-Options', 'sameorigin');
next();
},
其他可能的用途还包括为路由添加额外的安全层或请求验证。
版权所有 OpenJS Foundation 和 Node-RED 贡献者。保留所有权利。OpenJS Foundation 拥有并使用注册商标。有关 OpenJS Foundation 的商标列表,请参阅我们的 商标政策 和 商标列表。未在 OpenJS Foundation 商标列表 中列出的商标和徽标是其各自持有者的商标™或注册商标®。使用它们并不意味着与它们有任何关联或认可。
OpenJS Foundation | 使用条款 | 隐私政策 | OpenJS Foundation 章程 | 商标政策 | 商标列表 | Cookie 政策