在 git 存储库中处理密码的最佳实践是啥?

Posted

技术标签:

【中文标题】在 git 存储库中处理密码的最佳实践是啥?【英文标题】:What is the best practice for dealing with passwords in git repositories?在 git 存储库中处理密码的最佳实践是什么? 【发布时间】:2011-01-24 18:21:40 【问题描述】:

我有一个小 Bash 脚本,用于访问 twitter 并在某些情况下弹出 Growl 通知。使用脚本处理存储密码的最佳方法是什么?

我想将此脚本提交到 git 存储库并在 GitHub 上提供,但我想知道在执行此操作时保持我的登录名/密码私有的最佳方法是什么。目前,密码存储在脚本本身中。我无法在推送之前将其删除,因为所有旧提交都将包含密码。没有密码的开发不是一种选择。我想我应该将密码存储在外部配置文件中,但我想在尝试将某些东西放在一起之前,我会先检查一下是否有既定的方法来处理这个问题。

【问题讨论】:

【参考方案1】:

执行此操作的典型方法是从配置文件中读取密码信息。如果您的配置文件名为foobar.config,那么您将提交一个名为foobar.config.example 的文件到存储库,其中包含示例数据。要运行您的程序,您将使用您的真实密码数据创建一个名为foobar.config 的本地(未跟踪)文件。

要从以前的提交中过滤掉您现有的密码,请参阅Removing sensitive data 上的 GitHub 帮助页面。

【讨论】:

顺便说一句,您可以将示例 foobar.config 添加到 repo,然后将 foobar.config 添加到 .ignore 文件。这样,示例 foobar.config 将在克隆时出现,并且您的实际密码不会添加到存储库中。 @Mr_Chimp:.gitignore 文件不适用于已在存储库中的跟踪文件。例如,git add -u 将添加一个已更改的文件,即使它已经在 .gitignore 中。 作为补充,这里有一个有趣的链接,以防您不小心添加了配置文件并且想从 git 历史记录中删除它:help.github.com/articles/remove-sensitive-data 您将如何与您的团队共享这些密码?一件事是拥有一个本地副本(未提交到 repo),另一件事是与更大的团队共享它,甚至使用自动工具(用于部署等) 我和@dangonfast 有同样的问题。对于大型团队来说,这似乎并不实用。【参考方案2】:

Greg said 什么,但我要补充一点,签入文件 foobar.config-TEMPLATE 是个好主意。

它应该包含示例名称、密码或其他配置信息。那么真正的 foobar.config 应该包含什么就非常明显了,而无需查看所有代码,哪些值必须存在于 foobar.config 中,以及它们应该具有什么格式。

通常配置值可能不明显,例如数据库连接字符串和类似的东西。

【讨论】:

【参考方案3】:

如果您在 Rails 上使用 ruby​​,那么 Figaro gem 非常好、简单且可靠。它对生产环境的头痛系数也很低。

【讨论】:

您能否详细介绍一下该 gem 的功能?这样一来,它可以(可能)被视为适用于多种语言的“实践”。 medium.com/@MinimalGhost/… 有一个概述,它基本上似乎管理从配置文件中拉取东西【参考方案4】:

一种方法是使用环境变量设置密码(或 API 密钥)。 所以这个密码不受版本控制。

使用 Bash,您可以使用设置环境变量

export your_env_variable='your_password'

这种方法可以与Travis 等持续集成服务一起使用,存储在GitHub 存储库中的代码(无密码)可由 Travis 执行(使用环境变量设置密码)。

使用 Bash,您可以使用以下方法获取环境变量的值:

echo "$your_env_variable"

使用 Python,您可以使用以下方法获取环境变量的值:

import os
print(os.environ['your_env_variable'])

PS:请注意,这可能有点冒险(但这是一种很常见的做法)https://www.bleepingcomputer.com/news/security/javascript-packages-caught-stealing-environment-variables/

PS2:这篇标题为"How to securely store API keys" 的dev.to 文章可能会很有趣。

【讨论】:

如何防止潜在的“不安全”代码构建读取环境变量的内容? 我建议看看blog.travis-ci.com/2013-06-10-secure-env-in-pull-requests和docs.travis-ci.com/user/pull-requests/…【参考方案5】:

可以使用HashiCorp Vault 保护、存储和控制对令牌、密码、证书、API 密钥等的访问。

Ansible 还专门有一个 "Vault" feature(与 HashiCorp 产品无关)用于加密静态机密。

【讨论】:

与仅创建示例配置文件相比,我发现 Ansible Vault 确实过于复杂。 @icc97 是的,这很可悲。但是我们需要提到这种可能性。在我看来,对于比为单用户环境存储少量密码更复杂的任务,最好从一开始就使用专门的解决方案。 为了帮助未来的读者:Vault 和 Ansible Vault 是完全不同的不相关项目,但名称相似【参考方案6】:

这是我使用的一种技术:

我在我的主文件夹中创建了一个文件夹,名为: .config

在该文件夹中,我放置了我想要外部化密码和密钥的任意数量的配置文件。

我通常使用反向域名语法,例如:

com.example.databaseconfig

然后在 bash 脚本中我这样做:

#!/bin/bash
source $HOME/.config/com.example.databaseconfig ||exit 1

|| exit 1 会导致脚本在无法加载配置文件时退出。

我将该技术用于 bash、python 和 ant 脚本。

我很偏执,不认为 .gitignore 文件足够强大以防止无意签入。另外,没有任何监控它,所以如果确实发生了签到,没有人会发现来处理它。

如果特定应用程序需要多个文件,我会创建子文件夹而不是单个文件。

【讨论】:

【参考方案7】:

根据您的具体问题,处理存储库中的密码的方式会有所不同。

1。不要这样做。

一些回复中涵盖了避免这样做的方法 - .gitignore、config.example 等

.gitignore:存储在服务器等上,但不存储在 Git 上(弱解决方案) 环境变量:https://***.com/a/30664318/3070485 配置示例:https://***.com/a/2397905/3070485 命令行参数:程序启动时手动输入密码

或 2. 仅授权人员访问存储库

即被允许知道密码的人。 chmod 和用户组浮现在脑海中;还有一些问题,比如如果您在外部托管存储库或服务器,是否应该允许 Github 或 AWS 员工查看内容?

或 3. 加密敏感数据(本回复的目的)

如果您想将包含敏感信息(如密码)的配置文件存储在公共位置,则需要对其进行加密。这些文件在从存储库中恢复时可以被解密,甚至可以直接从它们的加密形式中使用。

使用加密配置数据的示例 javascript 解决方案如下所示。

const fs = require('fs');
const NodeRSA = require('node-rsa');

let privatekey = new NodeRSA();
privatekey.importKey(fs.readFileSync('private.key', 'utf8'));
const config = privatekey.decrypt(fs.readFileSync('config.RSA', 'utf8'), 'json');

console.log('decrypted: ', config);

因此,您只需编写几行 Javascript 即可恢复加密的配置文件。

请注意,将文件 config.RSA 放入 git 存储库将有效地使其成为二进制文件,因此它将失去 Git 之类的许多好处,例如能够选择对其进行更改。

解决方案可能是加密键值对或仅加密值。您可以加密所有值,例如,如果您有一个单独的敏感信息文件,或者如果您在一个文件中包含所有值,则只加密敏感值。 (见下文)

我上面的例子对任何想用它进行测试的人来说有点没用,或者作为一个例子开始,因为它假设存在一些 RSA 密钥和加密的配置文件config.RSA

所以这里添加了一些额外的代码行来创建 RSA 密钥和一个配置文件。

const fs = require('fs');
const NodeRSA = require('node-rsa');

/////////////////////////////
// Generate some keys for testing
/////////////////////////////

const examplekey = new NodeRSA(b: 2048);

fs.writeFileSync('private.key', examplekey.exportKey('pkcs8-private'));
fs.writeFileSync('public.key', examplekey.exportKey('pkcs8-public'));

/////////////////////////////
// Do this on the Machine creating the config file
/////////////////////////////

const configToStore = Goodbye: 'Cruel world';

let publickey = new NodeRSA();
publickey.importKey(fs.readFileSync('public.key', 'utf8'));

fs.writeFileSync('config.RSA', publickey.encrypt(configToStore, 'base64'), 'utf8');

/////////////////////////////
// Do this on the Machine consuming the config file
/////////////////////////////

let privatekey = new NodeRSA();
privatekey.importKey(fs.readFileSync('private.key', 'utf8'));

const config = privatekey.decrypt(fs.readFileSync('config.RSA', 'utf8'), 'json');
console.log('decrypted: ', config);

仅加密值

fs.writeFileSync('config.RSA', JSON.stringify(config,null,2), 'utf8');

您可以使用类似这样的方式解密具有加密值的配置文件。

const savedconfig = JSON.parse(fs.readFileSync('config.RSA', 'utf8'));
let config = ...savedconfig;
Object.keys(savedconfig).forEach(key => 
    config[key] = privatekey.decrypt(savedconfig[key], 'utf8');
);

通过将每个配置项放在单独的行上(例如上面的 HelloGoodbye),Git 将更好地识别文件中发生的事情,并将对信息项的更改存储为差异而不是完整的文件。 Git 也将能够更好地管理合并和樱桃挑选等。

但是,您越想对敏感信息进行版本控制更改,您就越倾向于安全存储库解决方案 (2) 并远离加密信息 (3) 解决方案。

【讨论】:

【参考方案8】:

信任但验证。

.gitignore 中,这将从存储库中排除“安全”目录:

secure/

但我分享@Michael Potter 的偏执狂。因此,为了验证 .gitignore,这里有一个 Python 单元测试,如果这个“安全”目录被签入,它会发出警报。为了检查,一个合法的目录也被测试了:

def test_github_not_getting_credentials(self):
    safety_url = 'https://github.com/BobStein/fliki/tree/master/static'
    danger_url = 'https://github.com/BobStein/fliki/tree/master/secure'

    self.assertEqual(200, urllib.request.urlopen(safety_url).status)

    with self.assertRaises(urllib.error.HTTPError):
        urllib.request.urlopen(danger_url)

【讨论】:

以上是关于在 git 存储库中处理密码的最佳实践是啥?的主要内容,如果未能解决你的问题,请参考以下文章

将 Play 代码从 git 存储库部署到生产环境的最佳实践是啥?

使用 ML Studio API 开发 CD/CI 的最佳实践是啥?

Git:将“git clone”到现有文件夹的最佳实践是啥?

MVC 验证 - 使用服务层保持 DRY - 最佳实践是啥?

在鼓励使用特殊字符的密码等字段的 REST API 中,避免 WAF 误报的最佳编码实践是啥

iOS 开发中 Info.plist 变量的最佳实践是啥?