我们看到无论是响应式编程框架 React,还是测试用的 Jest、Puppeteer 工具,亦或是做代码检查和样式优化的 ESLint、Prettier 工具,都离不开第三方库,而我们在之前的例子中,都是通过 NPM 下载和安装工具的。
包的发布
NPM(Node Package Manager)虽然它叫做 Node 包管理,但是其实你也可以用它管理或发布用 JavaScript 以外的语言编写的程序的包。
在 NPM 中,有两个核心的概念,一个是包(package),另外一个是模块(module)。
包是一个含有 package.json 文件的文件夹。package.json 的作用是对包中的文件或目录的描述。一个包必须含有一个 package.json 文件才能发布到 NPM 的注册列表。
模块是任何可以被 Node.js 的 require() 加载的文件或目录。能够被成功加载的模块必须是一个带有 main 字段的 pakcage.json 的目录,或者一个 JavaScript 的文件。
一个包的发布很简单,首先在命令行通过创建 mkdir 和改变目录 cd 的命令,我们可以创建一个包的文件夹,并导航到包的根目录。
在目录下,我们可以创建一个 package.json 的文件。
package.js 文件的创建方式有两种,一种是直接创建,另外一种是在命令行上执行 npm init 的命令,通过提示输入后,生成 package.json 的文件。
exports.printMsg = function() {
console.log("This is a message from the demo package");
}
在我们创建了一个包之后,在正式发布前,最好先通过 npm install 自己测试一下。确保无误之后,我们可以通过 npm publish 对包进行发布。无论是公开还是私有包的发布,都需要在发布前在 NPM 的注册页面上创建一个用户。为了安全,发布包以前,最好通过 2FA 的双因子认证。
包的持续集成和部署
在 DevOps,我们经常强调 CI/CD 的持续集成和部署。在使用 NPM 的时候,我们也可以通过访问令牌的方式来代替用户名和密码的认证方式。这里的访问令牌是一个十六进制字符串,我们可以使用它来进行身份验证、安装或发布模块。通过这种方式,我们可以让其它工具,例如持续集成测试环境访问 NPM 的包。当我们的工作流在运行时,它可以完成包括安装私有包的任务。
一种是传统令牌,另外一种是粒度令牌。
其中,传统令牌主要分为 3 类,一种是只读的,它只可以下载包;第二种是在下载的基础上可以安装;第三种是在前两种的基础上可以发布包。但是从安全的角度考虑,粒度令牌,顾名思义,有更细粒度的权限管理。粒度令牌还可以更好地区分可以访问的包和范围,授权给指定的组织,设置过期时间,基于 CIDR 的方法来控制授权的 IP 范围,并且提供只读和读写的权限选项。
举个例子,我们可以通过下面的方式,创建一个基于 IP 范围的访问令牌。
npm token create --cidr=192.0.2.0/24
之后,我们可以将令牌设置为 CI/CD 服务器中的环境变量或密钥。例如,在 GitHub Actions 中,我们可以将令牌添加为密钥。然后根据该密钥,创建一个名为 NPM_TOKEN 的环境变量,将密钥提供给工作流。
steps:
- run: |
npm install
- env:
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
这里值得强调的是,这里的令牌具有可以读取私有包,代表我们发布新包,更改用户或包设置的权限。所以从安全的角度考虑,我们必须保护好令牌。千万不能将令牌添加到版本控制或存在不安全的地方。最好是将令牌存储在密码管理器、云提供商的安全存储或 CI/CD 工具提供的安全存储器中。如果可能,应该使用我们前面讲到的具有最低权限的粒度访问令牌,并为令牌设置较短的过期时间。
包的管理
前面,我们说过,对于包的权限,我们可以选择公开或者私有化。无论是哪种模式下,我们都可以对用户和组织进行管理。
区别只是在于,公开的包所有人都可以读取和下载;而私有的包,无论是读取下载还是写入发布,都需要指定的用户或组织,才能赋予权限。下面,我们就来看看,如何在 NPM 中对组织进行管理。
首先,我们在登录后,点击头像可以选择创建一个组织,之后,我们需要给组织起一个名字。
私有和公有,个人账户和组织账户。群成员管理,及访问权限管理。
安全考虑
前面,我们学习了 NPM 的发布、CI/CD 和管理的流程。下面,我们再来看看 NPM 的安全考虑。在使用 NPM 的时候,很重要的一点就是安全考量。这里,我们可以从开发者和使用者两个不同的角度来看。
首先,我们先从开发者的角度来看,这里最需要警惕的就是我们的账户安全。
保护帐户安全的最佳方法就是我们前面提到的启用双因子身份验证(2FA)。
在此基础上,安全性最强的选项是使用安全密钥,无论是内置于设备还是外部硬件的密钥。安全密钥可以将身份验证绑定到正在访问的站点,大大降低网络钓鱼的风险。但因为并不是所有人都可以访问到安全密钥,所以 NPM 还支持为 2FA 生成一次性密码的身份验证应用程序。
盗取帐户的另一种方法是,通过使用过期域名作为电子邮件地址来识别帐户。攻击者可以注册过期的域名并重新创建用于注册帐户的电子邮件地址。通过访问帐户的注册电子邮件地址,攻击者可以通过重置密码来盗取不受 2FA 保护的帐户。NPM 也会定期检查帐户电子邮件地址是否有过期的域名或无效的 MX 记录。域名在过期之后,NPM 会禁用帐户进行密码重置,并要求用户在重置密码之前进行帐户恢复或成功通过身份验证的流程。需要注意的是,作为包的维护者,在你更新电子邮箱地址的时候,存储在包的公共元数据中的电子邮箱地址是不会更新的。由于这种抓取公共元数据以识别易受过期域名影响的帐户将导致误报,因此这些帐户看似易受攻击,但实际上并非如此。
从使用者的角度来看看。攻击者可能会试图通过注册与流行软件包名称相似的软件包来诱骗他人安装恶意软件包,希望人们因为笔误输入错误的名称,或者用其它的方式混淆两者。解决办法就是使用范围包(scoped package),以确保私有包不会被公共注册表中的包取代。
另外一个问题是对现有包的恶意更改行为,在这里,攻击者也有可能不会诱骗用户使用类似名称的软件包,而是试图将恶意行为添加到现有的流行软件包中。为了解决这个问题,NPM 也在与微软合作,扫描软件包中已知的恶意内容,并运行软件包来寻找潜在的新的恶意行为模式。这使得 NPM 包中带有恶意内容的比例大幅减少。此外,NPM 的信任和安全团队会检查并删除用户报告的恶意行为和内容。
此文章为2月Day16学习笔记,内容来源于极客时间《Jvascript进阶实战课》,大家共同进步💪💪
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。