cs.fyi 2023-03-14
如果你构建Web应用程序,不可避免地会有需要保护的密码或密钥。在这篇文章中,我们将分解从糟糕到行业最佳实践的5个层次的密钥管理。通过本指南,你将准备好为下一个项目正确管理凭证。
第0级:硬编码密钥
将密钥直接硬编码进代码是最糟糕的选择。尽管有更极端的可能性,比如完全关闭身份验证,但这仍然被认为是密钥管理中最糟糕的做法。在这个级别上,你会把密码直接放在代码中需要的地方。
例如,如果你正在用MongoDB数据库构建一个Node.js应用,你可以把你的密码放入以下行:
const dbClient = new MongoClient(process.env.MONGODB_URI, {
useNewUrlParser: true,
useUnifiedTopology: true,
auth: {
user: 'admin',
password: 'mypassword',
},
});
然而,这是一个非常糟糕的想法。其中一些最大的缺点包括:
- 私人信息分散在整个代码库中,使得日后返回修改变得困难。
- 即使Git仓库是私有的,所有参与项目的开发者都必须克隆仓库并在他们的系统上存储一份密钥的副本。
- 支持多个环境(如开发、测试或生产环境)很困难。
第1级:提取密钥到单独的配置文件
在此级别,我们创建一个包含数据库密码的config.env文件。然后使用类似dotenv的包将其作为环境变量加载。这是存储开发凭证密钥的首选方式。但是,对于生产凭证来说,它并不那么安全。
// config.env
DATABASE_PASSWORD = mypassword
DATABASE_USER = admin
// app.js
const dbClient = new MongoClient(process.env.MONGODB_URI, {
useNewUrlParser: true,
useUnifiedTopology: true,
auth: {
user: process.env.DATABASE_USER,
password: process.env.DATABASE_PASSWORD
},
});
将密钥提取到单独的配置文件中的好处包括:
- 没有秘密字符串漂浮在项目各处的更清晰代码。
- 可能拥有针对不同环境的单独配置文件。
- 你会知道所有密钥的位置,并且我们可以相应调整我们的行为。
第2级:在提交到仓库之前加密
如果需要在仓库中存储密钥,则至少可以加密密钥文件。例如,使用OpenSSL将纯文本配置文件转换为加密文件。
openssl aes-256-cbc -in mypassword.txt -out mypassword.txt.enc
虽然这种方法优于硬编码密钥,但加密密钥本身变成了一个敏感的秘密。你需要保证加密密钥的安全。
第3级:使用专用密钥管理器
利用由云提供商提供的专用密钥管理器的优势在于能够在单一位置管理密钥。密钥可以被审计,因此你可以跟踪谁访问了每个密钥,并且它们也可以有多个版本。
许多云提供商提供了一个安全管理加密密钥的密钥管理系统。例如,Google Cloud密钥管理器或AWS Secrets Manager。
密钥可以通过以下方式检索:
gcloud secrets versions access latest --secret=my-secret
第4级:使用HashiCorp Vault与临时凭证
最安全的密钥管理选项是使用带有临时凭证的HashiCorp Vault。这一层确保密钥仅在有限时间内有效。
Vault为每个请求的资源生成新的用户名和密码。当不再需要资源时,用户名和密码会自动撤销。
此过程通过API请求自动化完成,因此整个任务由你的应用程序无缝管理。要使这个系统工作,可以使用其中一个HashiCorp Vault客户端,如Node.js库。
结论
保护密钥对于Web应用程序至关重要,有许多不同的方法来实现。不同的系统有不同的安全性和保护程度,所以选择哪个层级取决于你的具体需求。
我们覆盖了密钥管理的五个层次,从最差的选择到最好的。虽然并不是所有的项目都需要或实际可行达到第4级。希望你能找到适合你凭证的安全水平,在安全与便利之间取得适当的平衡。