默认情况下,Node-RED 编辑器不安全——任何能够访问其 IP 地址的人都可以访问编辑器并部署更改。
这仅适用于您在受信任网络上运行的情况。
本指南介绍了如何保护 Node-RED。安全分为三个部分:
要通过 HTTPS(而非默认的 HTTP)访问 Node-RED 编辑器,您可以使用设置文件中的 https
配置选项。
从 Node-RED 1.1.0 开始,https
选项可以是一组静态配置选项,也可以是返回选项的函数。
完整的选项集在此处有文档说明。
选项至少应包括:
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
。
编辑器和管理 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。它们封装了一些特定于策略的详细信息,使其更易于使用。但它们也可以用作与其他类似策略进行身份验证的模板。
以下示例展示了如何在不使用我们提供的身份验证模块的情况下配置 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
。例如,如果您通过 https://:1880
访问编辑器,您将使用 https://:1880/auth/strategy/callback
。
默认情况下,callbackURL
将侦听 GET
请求。要改用 POST
请求,请将 callbackMethod
设置为 POST
。
上面的示例配置将阻止任何人访问编辑器,除非他们登录。
在某些情况下,允许所有人一定程度的访问是可取的。通常,这将是授予编辑器只读访问权限。为此,可以将 default
属性添加到 adminAuth
设置中以定义默认用户:
adminAuth: {
type: "credentials",
users: [ /* list of users */ ],
default: {
permissions: "read"
}
}
在 Node-RED 0.14 之前,用户可以拥有以下两种权限之一:
*
- 完全访问read
- 只读访问从 Node-RED 0.14 开始,权限可以更加细粒度,为了支持这一点,该属性可以是像以前一样的单个字符串,也可以是包含多个权限的数组。
管理 API 的每个方法都定义了访问它所需的权限级别。权限模型是基于资源的。例如,要获取当前流程配置,用户将需要 flows.read
权限。但要更新流程,他们将需要 flows.write
权限。
默认情况下,访问令牌在创建后 7 天过期。我们目前不支持刷新令牌以延长此期限。
可以通过设置 adminAuth
设置的 sessionExpiryTime
属性来自定义过期时间。这定义了令牌的有效时间(以秒为单位)。例如,将令牌设置为 1 天后过期:
adminAuth: {
sessionExpiryTime: 86400,
...
}
设置 adminAuth
属性后,管理 API 文档描述了如何访问 API。
除了将用户硬编码到设置文件中,还可以插入自定义代码来验证用户。这使得与现有身份验证方案集成成为可能。
以下示例展示了如何使用外部模块来提供自定义身份验证代码。
<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
属性设置为加载此模块: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) {
// 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=<ACCESS_TOKEN>
。编辑器将在本地存储该令牌并将其用于所有未来的请求。
HTTP In 节点公开的路由可以使用基本身份验证进行保护。
您 settings.js
文件中的 httpNodeAuth
属性可用于定义允许访问路由的单个用户名和密码。
httpNodeAuth: {user:"user",pass:"$2a$08$zZWtXTja0fB1pzD4sHCMyOCMYz2Z6dNbM6tl8sJogENOMcxWV9DN."},
pass
属性使用与 adminAuth
相同的格式。有关更多信息,请参阅生成密码哈希。
通过 httpStaticAuth
属性(使用相同格式)可以保护 httpStatic
属性定义的任何静态内容的访问。
pass
属性预期为 MD5 哈希。这在密码学上是不安全的,因此已被 bcrypt 取代,与 adminAuth
使用的相同。为了向后兼容,仍然支持 MD5 哈希——但不推荐使用它们。可以提供自定义 HTTP 中间件,该中间件将添加到所有 HTTP In
节点之前,并且从 Node-RED 1.1.0 开始,将添加到所有管理/编辑器路由之前。
对于 HTTP In
节点,中间件作为 httpNodeMiddleware
设置提供。
以下设置是限制 HTTP 输入节点中 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();
},
其他可能的用途是为路由添加额外的安全层或请求验证。
版权所有 OpenJS 基金会和 Node-RED 贡献者。保留所有权利。OpenJS 基金会拥有注册商标并使用商标。有关 OpenJS 基金会商标列表,请参阅我们的商标政策和商标列表。未在OpenJS 基金会商标列表中指明的商标和徽标是其各自所有者的商标™或注册®商标。使用它们不表示与它们有任何关联或得到它们的认可。
OpenJS 基金会 | 使用条款 | 隐私政策 | OpenJS 基金会章程 | 商标政策 | 商标列表 | Cookie 政策