如何在PHP中保护数据库密码?

当PHP应用程序建立数据库连接时,当然通常需要传递登录名和密码。如果我对我的应用程序使用一个最小权限的登录,那么PHP需要知道这个登录名和密码。保护密码的最好方法是什么?只在PHP代码中编写它似乎不是一个好主意。

238100 次浏览

将它们存储在web根目录外的一个文件中。

一些人误以为这是一个关于如何在数据库中商店密码的问题。这是错误的。它是关于如何存储密码,让你得到数据库。

通常的解决方案是将密码从源代码移到配置文件中。然后,将管理和保护配置文件的工作交给系统管理员。这样,开发人员就不需要知道任何关于产品密码的信息,并且在源代码控制中也没有密码记录。

将数据库密码放在一个文件中,使其对提供文件的用户只读。

除非您有某种方法只允许php服务器进程访问数据库,否则这几乎就是您所能做的全部工作。

如果谈论的是数据库密码,而不是来自浏览器的密码,标准的做法似乎是将数据库密码放在服务器上的PHP配置文件中。

您只需要确保包含密码的php文件具有适当的权限即可。也就是说,它应该是可读的只有web服务器和您的用户帐户。

只是把它放在配置文件的某个地方是通常完成的方式。只要确保你:

  1. 禁止从网络外的任何服务器访问数据库,
  2. 注意不要意外地向用户显示密码(在错误消息中,或通过PHP文件意外地作为HTML提供,等等)。

你的选择是有限的,因为你说你需要密码来访问数据库。一种常用的方法是将用户名和密码存储在单独的配置文件中,而不是主脚本中。然后确保将其存储在主web树之外。这是如果有一个web配置问题,让你的php文件只是显示为文本,而不是执行,你还没有暴露密码。

除此之外,你是在正确的行与最小的访问所使用的帐户。再加上

  • 不要使用用户名/密码的组合
  • 将数据库服务器配置为只接受来自该用户的web主机的连接(如果DB在同一台机器上,localhost更好),这样即使凭证暴露出来,它们对任何人都没有用处,除非他们有其他访问机器的权限。
  • 混淆密码(即使是ROT13也可以),如果有人访问了文件,它不会提供太多的防御,但至少可以防止随意查看它。

彼得

如果你正在使用PostgreSQL,那么它会自动在~/.pgpass中查找密码。更多信息请参见手动

一个额外的技巧是使用一个PHP单独的配置文件,如下所示:

<?php exit() ?>


[...]


Plain text data including password

这并不妨碍您正确地设置访问规则。但如果你的网站被黑客攻击,“要求”或“包括”将在第一行退出脚本,因此更难获得数据。

然而,不要让配置文件在可以通过web访问的目录中。你应该有一个“Web”文件夹,包含你的控制器代码,css,图片和js。这是所有。其他的都放在脱机文件夹中。

对于非常安全的系统,我们在配置文件中加密数据库密码(该文件本身由系统管理员保护)。在应用程序/服务器启动时,应用程序会提示系统管理员输入解密密钥。然后从配置文件中读取数据库密码,解密并存储在内存中以供将来使用。仍然不是100%安全,因为它存储在内存中解密,但你必须在某些时候称它“足够安全”!

是否可以在存储凭据的同一文件中创建数据库连接。将凭据内联到connect语句中。

mysql_connect("localhost", "me", "mypass");

否则,最好在connect语句之后取消设置凭据,因为不在内存中的凭据不能是凭记忆阅读;)

include("/outside-webroot/db_settings.php");
mysql_connect("localhost", $db_user, $db_pass);
unset ($db_user, $db_pass);

最好的方法是根本不存储密码!< br > 例如,如果您在Windows系统上,并连接到SQL Server,您可以使用集成身份验证连接到数据库,而不需要密码,使用当前进程的标识

如果你确实需要使用密码连接,首先加密它,使用强加密(例如使用AES-256,然后保护加密密钥,或使用非对称加密并让操作系统保护证书),然后使用强大的acl将它存储在配置文件中(在web目录之外)。

如果你在别人的服务器上托管,在你的webroot之外没有访问权限,你可以把你的密码和/或数据库连接放在一个文件中,然后使用.htaccess锁定文件:

<files mypasswdfile>
order allow,deny
deny from all
</files>

最安全的方法是在PHP代码中完全不指定这些信息。

如果你使用Apache,这意味着在httpd.conf或虚拟主机文件中设置连接细节。如果你这样做,你可以不带参数地调用mysql_connect(),这意味着PHP永远不会输出你的信息。

这是你在这些文件中指定这些值的方法:

php_value mysql.default.user      myusername
php_value mysql.default.password  mypassword
php_value mysql.default.host      server

然后像这样打开mysql连接:

<?php
$db = mysqli_connect();

或者像这样:

<?php
$db = mysqli_connect(ini_get("mysql.default.user"),
ini_get("mysql.default.password"),
ini_get("mysql.default.host"));

这个解决方案是通用的,因为它对开放源代码和闭源应用程序都有用。

  1. 为应用程序创建一个操作系统用户。看到http://en.wikipedia.org/wiki/Principle_of_least_privilege
  2. 用密码为该用户创建一个(非会话)操作系统环境变量
  3. 作为该用户运行应用程序

优点:

  1. 您不会意外地将密码检入源代码控制,因为您不能这样做
  2. 您不会意外地搞砸文件权限。你可能会,但这不会影响这个。
  3. 只能由root或该用户读取。Root可以读取你所有的文件和加密密钥。
  4. 如果使用加密,如何安全地存储密钥?
  5. 作品x-platform
  6. 请确保不要将envvar传递给不受信任的子进程

这个方法是Heroku提出的,他很成功。

我们是这样解决的:

  1. 在服务器上使用memcache,与其他密码服务器打开连接。
  2. 将密码(甚至所有加密的password.php文件)和解密密钥保存到memcache中。
  3. 该网站调用memcache键保存密码文件,并在内存中解密所有密码。
  4. 密码服务器每5分钟发送一次新的加密密码文件。
  5. 如果在项目中使用加密的password.php,则需要进行审计,检查该文件是否被外部接触或查看。当发生这种情况时,您可以自动清理内存,以及关闭服务器以供访问。

之前,我们将DB user/pass存储在配置文件中,但后来使用了偏执模式——采用纵深防御策略。

如果您的应用程序被泄露,用户将拥有对您的配置文件的读访问权,因此黑客就有可能读取这些信息。配置文件也可能在版本控制中被捕获,或者在服务器中被复制。

我们已经切换到在Apache VirtualHost中设置的环境变量中存储user/pass。这个配置只能由根用户读取——希望您的Apache用户不是以根用户身份运行。

这样做的缺点是,现在密码在一个全局PHP变量中。

为了降低这种风险,我们有以下预防措施:

  • 密码已加密。我们扩展了PDO类以包括解密密码的逻辑。如果有人阅读了我们建立连接的代码,那么连接是用加密的密码建立的,而不是密码本身,这一点并不明显。
  • 加密的密码从全局变量移动到私有变量应用程序立即这样做,以减少值在全局空间中可用的窗口。
  • phpinfo()被禁用。 PHPInfo是一个很容易获得所有内容概览的目标,包括环境变量。

实际上,最好的做法是将数据库凭据存储在环境变量中,因为:

  • 这些凭据依赖于环境,这意味着您在dev/prod中不会有相同的凭据。将它们存储在所有环境的同一个文件中是错误的。
  • 凭据是与业务逻辑无关,这意味着登录名和密码在你的代码中没有任何关系。
  • 您可以在不创建任何业务代码类文件的情况下设置环境变量,这意味着您永远不会犯在Git中向提交中添加凭据文件的错误。
  • 环境变量是超全局变量:您可以在代码中的任何地方使用它们,而不包括任何文件。

如何使用它们?

    使用$_ENV数组:
    • 设置:$_ENV['MYVAR'] = $myvar
    • __abc1: __abc0
    使用php函数:
  • 在vhosts文件和。htaccess中,但不建议这样做,因为它在另一个文件中,并不能通过这样做来解决问题。

你可以很容易地删除一个文件,比如envars .php,里面有所有的环境变量,然后执行它(php envvars.php)并删除它。这有点老派,但它仍然可以工作,而且服务器中没有任何带有凭据的文件,代码中也没有凭据。由于这有点费力,框架做得更好。

Symfony的例子(不只是PHP) 像Symfony这样的现代框架建议使用环境变量,并将它们存储在.env不提交的文件中或直接存储在命令行中,这意味着你可以这样做:

文档: