繁体   English   中英

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

[英]How to secure database passwords in PHP?

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

一些人将此误读为关于如何在数据库中存储密码的问题。 那是错的。 它是关于如何存储让您访问数据库的密码。

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

如果您托管在其他人的服务器上并且在您的 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"));

将它们存储在 Web 根目录之外的文件中。

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

此解决方案是通用的,因为它对开源和闭源应用程序都很有用。

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

好处:

  1. 您不会意外地将密码检查到源代码管理中,因为您不能
  2. 您不会意外搞砸文件权限。 嗯,你可能会,但它不会影响这个。
  3. 只能由 root 或该用户读取。 无论如何,root 都可以读取您的所有文件和加密密钥。
  4. 如果您使用加密,您如何安全地存储密钥?
  5. 适用于 x 平台
  6. 确保不要将 envvar 传递给不受信任的子进程

这个方法是 Heroku 推荐的,非常成功。

如果可以在存储凭据的同一文件中创建数据库连接。 在连接语句中内联凭据。

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

否则最好在 connect 语句之后取消设置凭据,因为不在内存中的凭据无法从内存中读取;)

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

以前我们将数据库用户/密码存储在配置文件中,但此后已进入偏执模式——采用深度防御策略。

如果您的应用程序受到威胁,用户将拥有对您的配置文件的读取权限,因此破解者有可能读取此信息。 配置文件也可能陷入版本控制,或在服务器上复制。

我们已经切换到在 Apache VirtualHost 中设置的环境变量中存储用户/密码。 这个配置只能被 root 读取——希望你的 Apache 用户没有以 root 身份运行。

与此相反的是,现在密码在全局 PHP 变量中。

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

  • 密码是加密的。 我们扩展 PDO 类以包含解密密码的逻辑。 如果有人阅读了我们建立连接的代码,那么很明显连接是使用加密密码而不是密码本身建立的。
  • 加密的密码从全局变量移动到私有变量应用程序立即执行此操作以减少该值在全局空间中可用的窗口。
  • phpinfo()被禁用。 PHPInfo 是一个简单的目标,可以了解所有内容,包括环境变量。

如果您使用的是 PostgreSQL,那么它会自动在~/.pgpass查找密码。 有关更多信息,请参阅手册

您的选择是有限的,因为您说访问数据库需要密码。 一种通用方法是将用户名和密码存储在单独的配置文件而不是主脚本中。 然后确保将其存储在主网络树之外。 那是如果存在 Web 配置问题,使您的 php 文件仅显示为文本而不是被执行,则您没有公开密码。

除此之外,您处于正确的行上,对正在使用的帐户的访问权限最小。 添加到那个

  • 不要将用户名/密码组合用于其他任何用途
  • 将数据库服务器配置为仅接受来自该用户的 Web 主机的连接(如果数据库位于同一台计算机上,则 localhost 甚至更好)这样即使公开了凭据,它们也不会对任何人有用,除非他们有其他访问权限机器。
  • 混淆密码(即使 ROT13 也可以),如果某些人确实可以访问该文件,它不会提供太多防御,但至少可以防止随意查看它。

彼得

我们是这样解决的:

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

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

除非您有某种方法只允许 php 服务器进程访问数据库,否则您几乎可以做到这一点。

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

<?php exit() ?>

[...]

Plain text data including password

这不会阻止您正确设置访问规则。 但是如果您的网站被黑,“require”或“include”只会在第一行退出脚本,因此获取数据更加困难。

然而,永远不要将配置文件放在可以通过 Web 访问的目录中。 您应该有一个“Web”文件夹,其中包含您的控制器代码、css、图片和 js。 就这样。 其他任何内容都在脱机文件夹中。

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

您只需要确保包含密码的 php 文件对其具有适当的权限。 即它应该只能由 Web 服务器和您的用户帐户读取。

通常的做法是将它放入某个配置文件中。 只要确保你:

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

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

如果你需要一个密码时,先进行加密连接,使用强大的加密(例如,使用AES-256,然后保护加密密钥,或使用非对称加密,并有操作系统保护证书),然后将其存储在一个具有强 ACL 的配置文件(在 web 目录之外)。

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

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

如何使用它们?

  • 使用 $_ENV 数组:
    • 设置: $_ENV['MYVAR'] = $myvar
    • 得到echo $_ENV["MYVAR"]
  • 使用php函数:
    • 使用putenv("MYVAR=$myvar");函数设置 - putenv("MYVAR=$myvar");
    • 使用getenv 函数- getenv('MYVAR');
  • 在 vhosts 文件和 .htaccess 中,但不建议这样做,因为它在另一个文件中,并且通过这种方式无法解决问题。

您可以轻松地删除包含所有环境变量的文件,例如 envvars.php 并执行它( php envvars.php )并删除它。 这有点老派,但它仍然有效,并且您在服务器中没有任何带有凭据的文件,并且代码中没有凭据。 由于它有点费力,框架做得更好。

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

文件:

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM