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

How to secure database passwords in PHP?

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


有几个人把这理解为一个关于如何在数据库中存储密码的问题。那是错误的。它是关于如何存储允许您访问数据库的密码。

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


如果您托管在其他人的服务器上,并且在您的Webroot之外没有访问权限,则可以始终将密码和/或数据库连接放在文件中,然后使用.htaccess锁定文件:

1
2
3
4
<files mypasswdfile>
order allow,deny
deny from all
</files>


最安全的方法是根本不要在PHP代码中指定信息。

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

以下是在这些文件中指定这些值的方式:

1
2
3
php_value mysql.default.user      myusername
php_value mysql.default.password  mypassword
php_value mysql.default.host      server

然后打开MySQL连接,如下所示:

1
2
<?php
$db = mysqli_connect();

或者像这样:

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


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


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


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

  • 为应用程序创建操作系统用户。请参阅http://en.wikipedia.org/wiki/principle-of-least-u特权
  • 使用密码为该用户创建(非会话)OS环境变量
  • 以该用户身份运行应用程序
  • 优势:

  • 您不会意外地将密码检查到源代码管理中,因为您不能
  • 您不会意外地破坏文件权限。嗯,你可能会,但这不会影响到这个。
  • 只能由根用户或该用户读取。根可以读取所有文件和加密密钥。
  • 如果使用加密,如何安全地存储密钥?
  • 工程X平台
  • 确保不要将envvar传递给不受信任的子进程
  • 这个方法是由非常成功的Heroku提出的。


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

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

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

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


    您的选择是有限的,正如您所说,您需要密码来访问数据库。一种通用的方法是将用户名和密码存储在单独的配置文件中,而不是主脚本中。然后一定要将其存储在主Web树之外。也就是说,如果存在Web配置问题,使您的PHP文件只显示为文本而不是执行,那么您还没有暴露密码。

    除此之外,您在正确的线路上,对正在使用的帐户的访问权限最小。加上这个

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

    彼得


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


    以前我们把db user/pass存储在一个配置文件中,但后来又进入了偏执模式——采用了深度防御策略。

    如果您的应用程序受到威胁,那么用户将具有对您的配置文件的读取权限,因此可能有黑客读取此信息。配置文件也可以被版本控制捕获,或者在服务器周围复制。

    我们已经切换到存储在ApacheVirtualHost中设置的用户/传递环境变量。这个配置只能由根目录读取——希望您的Apache用户没有以根目录运行。

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

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

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

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

    除非您有一些只允许PHP服务器进程访问数据库的方法,否则这几乎是您所能做的。


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

    您只需要确保包含密码的PHP文件对其具有适当的权限。也就是说,它只能由Web服务器和您的用户帐户读取。


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

    如果您确实需要使用密码进行连接,请首先使用强加密(例如使用AES-256,然后保护加密密钥,或者使用非对称加密并让操作系统保护证书)对其进行加密,然后将其存储在具有强ACL的配置文件(在Web目录之外)中。


    把它放在某个配置文件中通常是这样做的。只要确保你:

  • 禁止从网络之外的任何服务器访问数据库,
  • 注意不要意外地向用户显示密码(在错误消息中,或通过php文件意外地被用作html等)。

  • 我们以这种方式解决了这个问题:

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

  • 另一个技巧是使用一个php独立的配置文件,其外观如下:

    1
    2
    3
    4
    5
    <?php exit() ?>

    [...]

    Plain text data including password

    这并不妨碍您正确设置访问规则。但是,如果您的网站被黑客攻击,"require"或"include"只会在第一行退出脚本,因此更难获取数据。

    不过,不要让配置文件位于可以通过Web访问的目录中。您应该有一个"web"文件夹,其中包含您的控制器代码、CSS、图片和JS。这就是全部。脱机文件夹中还有其他内容。