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

use*_*359 395 php database security

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

use*_*318 234

有几个人误以为是关于如何在数据库中存储密码的问题.那是错的.它是关于如何存储允许您访问数据库的密码.

通常的解决方案是将密码从源代码中移出到配置文件中.然后将管理和保护配置文件保留给系统管理员.这样开发人员就不需要了解生产密码,也没有源代码控制中的密码记录.

  • 我同意配置需要得到适当的保护.但是,知道如何做到这一点是系统管理员的业务,而不是开发人员.在这种情况下,我不同意强加密的价值.如果您无法保护配置文件,您认为可以保护您的密钥的原因是什么? (27认同)
  • 请记住,即使存储在Web可访问目录之外的文件也必须由使用它们的脚本读取.如果有人包含该文件,然后从文件中转储数据,他们将看到密码. (14认同)
  • 我使用apache环境变量来设置路径,以便在源代码中甚至不知道文件的路径.这也很好地允许根据服务器上的Apache设置为开发和生产提供不同的密码 (11认同)
  • 我更喜欢使用只允许从Web服务器访问数据库的数据库帐户.然后我不打扰加密配置,我只是将它存储在Web根目录之外. (10认同)
  • 谢谢.如果我理解正确,那么php文件将包含配置文件,允许它使用密码.例如,我创建了一个名为"app1_db_cfg.php"的文件,用于存储登录名,pword和db名称.然后我的application.php页面包含'app1_db_cfg.php',我在做生意! (8认同)
  • 要首先避免此问题,请使用密码服务器并查询服务器以获取所需的信息。AWS KMS 可用于通过在文件系统中对密码进行加密来帮助进一步保护您的密码,并且仅使用 Redis 在内存中对其进行解密。https://aws.amazon.com/kms/ (3认同)
  • 对于所有问如何保护我以外的人,答案是要么自己管理整个公司,要么至少要信任一个人。 (2认同)
  • @henk 这个没有解决办法。您必须信任或小心所有发送到生产服务器的脚本的内容。 (2认同)
  • @tonix问题更多是与开源软件有关的问题,因为您将了解该文件的变量或布局。由于这个原因,`define`是设置这些变量的一个坏主意。(例如,WordPress使用这种不安全的方法,并且该方法将其存储在可通过Web访问的目录中。)我所指出的问题是,如果某人能够上传文件,则他们可以在该文件中发现密码。但是,即使有人可以轻松转储使用define创建的密码,Laravel的.env或基于数组的配置文件也要好一些。每个文件都容易受到攻击。 (2认同)
  • 话又说回来,如果有人可以将文件放在您的网站上并运行它,那么您将面临比丢失密码更大的问题。该文件可以做任何事情。 (2认同)

kel*_*len 102

如果您在其他人的服务器上托管并且无法访问您的webroot,您可以始终将您的密码和/或数据库连接放在一个文件中,然后使用.htaccess锁定该文件:

<files mypasswdfile>
order allow,deny
deny from all
</files>
Run Code Online (Sandbox Code Playgroud)

  • 当然,但如果有人有shell访问权限,那么您的整个帐户无论如何都会受到损害. (27认同)
  • @Porlune:开发人员应该让他们的版本控制系统忽略密码文件,即使用.gitignore.但是,应该注意包含敏感数据的文件. (6认同)
  • 这是不好的做法,因为您可能会意外地将凭据提交到存储库. (4认同)
  • 谢谢,这正是我想要的. (3认同)
  • @Ankit:如果不友好的人可以将文件上传到服务器并执行它,那么服务器没有正确配置。 (2认同)
  • @RobertTalada 对于这个特定的解决方案,重要的是那些安全实践背景有限的人必须警惕潜在的陷阱。浏览器中的用户字段超出了范围,但存储库提交则不然。 (2认同)

Lar*_*röm 42

最安全的方法是根本不具备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
Run Code Online (Sandbox Code Playgroud)

然后你打开你的mysql连接,如下所示:

<?php
$db = mysqli_connect();
Run Code Online (Sandbox Code Playgroud)

或者像这样:

<?php
$db = mysqli_connect(ini_get("mysql.default.user"),
                     ini_get("mysql.default.password"),
                     ini_get("mysql.default.host"));
Run Code Online (Sandbox Code Playgroud)

  • 是的,但任何用户(或黑客滥用写得不好的PHP脚本)都可以通过`ini_get()`读取密码. (4认同)
  • Marki555表示,可以运行PHP代码的攻击者也可以调用PHP函数,这显然是正确的,而且无法采取任何措施。我还想补充一点,我不再遵循我自己在此答案中给出的建议,而是使用环境变量。不过,概念很相似:不要将您的凭据存储在代码中,而是以某种方式注入它们。使用`ini_get()`或`getenv()`并不重要。 (2认同)
  • @DeepBlue如果可以注入ini_get(),也可以注入file_get_contents(anypath)。只要php有办法获取密码,任何恶意代码也会如此。 (2认同)
  • 我认为这是一个非常糟糕的主意,如果服务器上有一个 phpinfo() 浮动,这会泄露你的密码。 (2认同)

da5*_*5id 39

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

  • 而且,正如其他地方所提到的,在源代码控制之外. (29认同)
  • 我们可以包括它吗?例如在PHP中我们可以做`include('../ otherDirectory/configfile.conf')`? (5认同)
  • @TheGodfather 这个想法是新开发人员应该拥有自己的开发环境的凭证。虽然在代码中包含包含说明或注释的自述文件是一种很好的做法,指示您应该如何配置它(但不是实际数据)。 (3认同)
  • 你们都建议将凭据存储在 wwwroot 之外。好的,我了解安全背景。但它应该如何存储在版本控制中(示例配置)?通常 wwwroot 是 git repo 的根目录,因此如果有任何外部内容 - 它将位于 VC 之外。想象一下新的开发人员试图建立一个本地实例进行开发 - 他应该如何知道“获取这个文件,将其复制到外面并填写”之类的魔法? (2认同)

pda*_*vis 34

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

  • 如果管理员死了怎么办? (84认同)
  • @RaduMurzea那太荒谬了.你什么时候听说系统管理员死了?他们就像麦当劳,他们只是突然出现/消失! (33认同)
  • @Radu Murzea只有2个或更多的管理员,然后你就像raid阵列一样.一次失败多个驱动器的可能性要低得多. (13认同)
  • 什么时候服务器重启?唤醒管理员让他们在.etc.etc中输入密码需要多长时间.大声笑 (5认同)

Nei*_*gan 14

该解决方案是通用的,因为它对于开源和闭源应用都是有用的.

  1. 为您的应用程序创建OS用户.请参见http://en.wikipedia.org/wiki/Principle_of_least_privilege
  2. 使用密码为该用户创建(非会话)OS环境变量
  3. 以该用户身份运行应用程序

好处:

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

Heroku建议这种方法非常成功.


Bob*_*ger 11

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

mysql_connect("localhost", "me", "mypass");
Run Code Online (Sandbox Code Playgroud)

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

include("/outside-webroot/db_settings.php");  
mysql_connect("localhost", $db_user, $db_pass);  
unset ($db_user, $db_pass);  
Run Code Online (Sandbox Code Playgroud)

  • 如果有人可以访问内存,那么无论如何你都被搞砸了.这是毫无意义的假安全性.在webroot之外(或者至少受.htaccess保护,如果你没有访问webroot上面)是唯一安全的选择. (9认同)
  • @uliwitness - 这就像是说因为有人可以用乙炔火炬切断你的网络运营中心的锁意味着门也是假的安全.将敏感信息保持在最严格的范围内总是有意义的. (2认同)

Vag*_*err 7

您的选择有限,因为您说您需要密码才能访问数据库.一种通用方法是将用户名和密码存储在单独的配置文件中,而不是主脚本中.然后一定要将其存储在主Web树之外.那就是如果有一个Web配置问题,你的php文件只是显示为文本而不是被执行,你没有暴露密码.

除此之外,您使用的是正确的线路,并且对所使用的帐户的访问权限最小.加上那个

  • 不要将用户名/密码的组合用于其他任何事情
  • 将数据库服务器配置为仅接受来自该用户的Web主机的连接(如果数据库位于同一台计算机上,localhost甚至更好)这样即使凭证被公开,除非他们具有对其他人的访问权限,否则它们对任何人都没用.机.
  • 对密码进行模糊处理(即使ROT13会这样做)如果有人能够访问该文件,它也不会提供太多防御,但至少它会阻止随意查看它.

彼得


Jim*_*Jim 7

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


小智 7

我们是这样解决的:

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


Chr*_*ris 5

将数据库密码放在一个文件中,使其对服务文件的用户只读.

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


Jas*_*rth 5

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

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

  • 不幸的是,PHP 配置文件可以被 phpinfo() 读取,如果有人碰巧留下了一些测试脚本,幸运的攻击者将能够读取密码。最好将连接密码保留在 Web 服务器根目录之外的文件中。那么访问它的唯一方法是使用 shell 或执行任意代码,但在这种情况下,所有安全性都会丢失。 (2认同)

Mar*_*ijn 5

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

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


e-s*_*tis 5

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

<?php exit() ?>

[...]

Plain text data including password
Run Code Online (Sandbox Code Playgroud)

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

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

  • 您使用 fopen(),就像普通文本文件一样。 (3认同)
  • @e-satis 好的它会阻止黑客做`require`/`include`但是如何阻止做`fopen`? (2认同)

Cou*_*les 5

以前我们将DB user/pass存储在一个配置文件中,但后来又变成了偏执模式 - 采用了深度防御策略.

如果您的应用程序遭到入侵,则用户将具有对您的配置文件的读取权限,因此有可能让黑客读取此信息.配置文件也可以在版本控制中捕获,或者在服务器周围复制.

我们已经切换到存储用户/传递Apache VirtualHost中设置的环境变量.此配置只能由root读取 - 希望您的Apache用户不以root用户身份运行.

与此相关的是,现在密码是全局PHP变量.

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

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