安全

默认时,并没有对Node-RED编辑器进行任何保护,也就是说,任何人都可以通过访问其IP地址和端口,使用编辑器功能并改变和部署流程,因此,仅适用于在可信网络中运行的情况。

本章主要讲述如何对Node-RED进行保护,共分两个部分:

编辑器和管理API安全

为在编辑器和管理API部分启用用户身份验证功能,请在你的settings.js文件中加入以下内容:

adminAuth: {
    type: "credentials",
    users: [{
        username: "admin",
        password: "$2a$08$zZWtXTja0fB1pzD4sHCMyOCMYz2Z6dNbM6tl8sJogENOMcxWV9DN.",
        permissions: "*"
    }]
}

users属性为一个用户对象列表,允许你设定多个用户,并且为其设定不同的权限。

上例设置了一个名为admin的用户,其密码为password,在编辑器中具有全部权限,注意密码是经过加密的。

注意: 在以前发布的Node-RED中,可以通过设置httpAdminAuth启用HTTP基本用户身份验证功能,目前这个选项已被弃用,不应再使用了。

生成密码加密字串

可以利用node-red-admin命令行工具,生成适用的密码加密字串:

node-red-admin hash-pw

这个工具会提示你输入希望使用的密码,然后将生成的字串显示在屏幕上,你将其复制到设置文件中。

另外,你还可以通过在Node-RED安装目录中执行以下命令,实现同样的功能:

node -e "console.log(require('bcryptjs').hashSync(process.argv[1], 8));" your-password-here

设置默认用户

前面给出的设置会禁止所有未登录的用户访问编辑器。

而在某些情况下,可能需要向未登录的用户开放某些访问权限。比如最典型的,只读访问编辑器的权利等。要做到这点,可以在adminAuth设置项中,针对默认用户加入default属性:

adminAuth: {
    type: "credentials",
    users: [ /* list of users */ ],
    default: {
        permissions: "read"
    }
}

用户权限

对Node-RED 0.14之前的版本,用户只能具有以下两类权限的一项:

  • * - 完全访问
  • read - 只读访问

从Node-RED 0.14开始,可以对权限做细微调整,并且在以前支持的单字串属性基础上,加入对多权限数组的支持。

管理API中的每种方法都定义了不同级别的访问权限,其权限模型是基于资源设计的。比如,为了获取当前流程的设置,用户需要有flows.read权限,但如果想修改流程,则需要有flows.write权限。

令牌期限

默认情况下,访问令牌会在被创建七天后过期,目前我们还不能支持令牌更新和延期功能。

可以通过adminAuth设置项中的sessionExpiryTime属性自行设定过期时间,也就是在多长时间内,令牌是有效的,单位为秒。例如,将令牌设为一天内有效:

adminAuth: {
    sessionExpiryTime: 86400,
    ...
}

访问管理API

管理API文档中讲述了如何通过adminAuth属性来访问API。

自定义用户身份验证功能

除了在设置文件中对用户信息进行硬编码,也可以通过插入代码的方式验证用户身份,这就使得与其它用户认证方式整合成为可能。

以下实例显示了,如何利用一个外部模块,来提供个性化身份验证功能。

  • 将以下代码保存为<node-red>/user-authentication.js文件
var when = require("when");
module.exports = {
   type: "credentials",
   users: function(username) {
       return when.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 when.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 when.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"});
       });
   }
}
  • 在settings.js的adminAuth属性中加载该模块:
adminAuth: require("./user-authentication");

HTTP节点安全

HTTP In节点对外提供的访问路径可以通过基本身份验证的方式加以保护。

settings.js文件的httpNodeAuth属性中,可以单独设定访问该路径的用户名和密码。

httpNodeAuth: {user:"user",pass:"$2a$08$zZWtXTja0fB1pzD4sHCMyOCMYz2Z6dNbM6tl8sJogENOMcxWV9DN."},

pass属性所使用的格式与adminAuth相同,详情见生成密码加密字串

对于httpStatic属性中设定的静态内容的安全防护,可以通过httpStaticAuth属性实现,其格式也基本相同。

注意: 在以前版本的Node-RED中,pass属性采用了MD5加密方式, 因为它不够安全,所以采用了adminAuth所使用的加密方式来替代它。但为了保持兼容,MD5仍被支持,只是不建议再使用。