在配置文件中以明文形式存储MySQL密码的更好方法是什么?

38

一直以来,许多 PHP 程序要求用户在应用程序的根目录下的一个配置文件中以明文形式(在字符串或常量中)存储 mysql 密码,这一点一直让我感到困扰。

这些年过去了,是否有更好的方法呢?

到目前为止,我想出了两种最小安全增强措施:

  1. 使用 .htaccess 规则使文件在 Web 上不可读(以防 PHP 失败或存在安全漏洞以读取 PHP 源代码)。

  2. 在数据库连接完成后销毁内存中的密码(unset)(以防止安全漏洞、注入等导致的字符串泄露)。

但当然,这两种方法都不能解决原始问题。

谢谢您提供的其他想法!


虽然技术上不是一个答案,但你可以配置mysql只接受可信来源,例如只使用unix域套接字或只使用正确的SSL证书。关于这个话题:请参见我的答案,了解如何不存储明文密码。 - mvds
你有没有考虑过可能会有一些包含密码的 backup.(tgz|zip) 文件存在呢? - mvds
1
甚至比本地备份更糟糕的是带有文本的远程备份 - 这就是我提出问题的原因,因为纯文本迟早会引发麻烦。 - ck_
8个回答

25

就我个人而言,我会将一些敏感信息(比如数据库连接信息)存储在位于我的网站根目录之外的config.ini文件中。然后在我的index.php文件中,可以这样写:

$config = parse_ini_file('../config.ini');

这意味着如果您的服务器意外地将PHP脚本输出为纯文本(就像Facebook曾经那样),变量将不可见;只有PHP脚本才能访问这些变量。

这也不依赖于.htaccess文件,如果您的.htaccess文件被移动或损坏,则无法使用。

需要注意的是,添加于2017年2月14日:我现在会将配置参数存储为环境变量。我已经有一段时间没有使用.ini文件方法了。


12

将配置文件放在文档根目录之外是提高配置文件安全性的流行方法。


3
我正在打这个。我本来要指出一个从属子句,即很多,如果不是大多数共享主机都不会让客户访问文档根目录以外的任何内容。 - Peter O'Callaghan
你仍然在某个文件中存储了明文密码。这仍然是比你需要承担的风险更高的。 - mvds
1
彼得·奥卡拉汉,我有专用服务器,但我甚至不能在文档根目录之外存储。 - Nusrat Nuriyev

12

由于您的代码需要密码,因此没有完美的安全保障。但是您可以使其难以恢复。

我在我的Web配置文件中放置了一些哈希算法作为环境变量,例如MYSQL_PASS_HASH

然后我做了这样的事情:md5(getenv('MYSQL_PASS_HASH').'gibberish$qwefsdf'),这就是密码。当然,如果你很谨慎,你应该在此之后使用unsetenv

您的密码将不会被明文存储,只有在某人拥有您的Web配置文件以及数据库时才能恢复。

这个过程发生在Web根目录之外的一个文件中(不要把所有的信任都放在.htaccess中)。


我认为这是目前为止第一个真正改进纯文本的回复。下一个问题将是使其易于其他用户进行配置。在某些主机上,移动到webroot之外并不总是可能的,而且并不是真正的解决方案,因为如果它可以被包含,file_get_contents也会对其起作用。 - ck_
1
@symcbean: 为什么?我在这里发布它,就像我在自己的服务器上配置一样!这不是晦涩难懂的,而是在 SO 上公开发布的!我只是将风险分散到两个文件中,这两个文件都不应该被访问,并且永远不应该同时成为同一个备份的一部分,另外不以明文形式存储。 - mvds
9
“obscure” 部分的意思是简单地隐藏(问题),因此实际上,mvds您的方法在技术上比仅将纯文本移出Web根目录更好。仅仅移动文件肯定是“安全性靠混淆”。 - ck_

2
当然,您绝不能在文档根目录中的明文文件中存储密码。您采取进一步的保护措施将取决于您配置Web服务器的访问级别。
您可以在php.ini中定义密码(或通过Apache配置或.htaccess中的ini设置)。或者在启动Web服务器时将其设置为环境变量。
仅加密密码是没有意义的 - 这意味着您需要存储解密密钥 - 除非您使用用户提供的密码与“法定人数”身份验证一起解密密码(但这会防止未经身份验证的会话访问数据库,并且在需要添加新用户到“法定人数”时会变得混乱)。
如果它是一个便宜的托管包并且您没有可访问的文档根目录之外的存储,则在其中的PHP包含文件中存储密码应该可以防止其被暴露(文件将由php解析而不是下载)。另外,仅以'.ht'开头命名文件可能会防止远程访问。
请注意,您的第二个选项有些多余 - 如果有人可以对您的代码造成如此大的破坏,那么他们就不需要从运行代码中提取密码。
实际上,没有解决问题的方法。
C.

就像你一样,我得出了这是一个鸡蛋问题的结论,但我想看看这里的一些伟大思想家能想出什么其他的东西。 - ck_
在某种形式的加密中,明显存在一个点,即尽可能将恢复密码所需的两个(或多个)部分分开保管。(例如,一个部分位于“/etc”下,另一个部分位于您的包含路径中,但不在您的Web根目录中) - mvds

2

2
关于限制权限的提醒很好 - 因为许多 PHP 应用程序采取懒惰的方式,让用户只配置一个 MySQL 登录来创建表等。但是,即使是较低的权限,在大多数应用程序中仍需要进行写入,并且仅凭此就可以造成巨大的损害。 - ck_

1

如果你愿意为文件安全性牺牲可用性,你可以将配置文件中的密码删除,并要求管理员在启动时输入密码并将其存储在全局变量中。

你仍然需要确保自己免受可能导致该变量泄漏的注入攻击的影响,当然,在(重新)启动过程中还有一个手动步骤。


很遗憾,在典型的PHP/MySQL应用程序中无法实现此功能。 - ck_
同意,但我认为这是值得列出的解决方案。 - G__

0

它不必在Web根目录中。您可以将文件移动到Web根目录之外并以这种方式调用它。这只意味着该文件无法直接从Web中调用。

如果您的代码存在安全漏洞,例如未经过滤地包含GET数据,则该文件仍然面临风险。真正的关键是确保您的应用程序也是安全的。


0
你可以在 .htaccess 文件中设置环境变量,例如:
SetEnv DBuser sesame
SetEnv DBpass street

然后在你的代码中读取、使用和删除这些条目。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接