一些人将其误认为是关于如何在数据库中存储密码的问题。那是错的。它是关于如何存储让您访问数据库的密码。
通常的解决方案是将密码从源代码中移到配置文件中。然后将管理和保护该配置文件的工作留给您的系统管理员。这样开发人员就不需要知道任何有关生产密码的信息,并且在您的源代码管理中没有密码记录。
如果您托管在其他人的服务器上并且在您的 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"));
ini_get()
读取密码。
but any user (or a hacker abusing badly written php script) can read the password via ini_get()
你如何处理这个问题?
ini_get()
还是 getenv()
并不重要。
将它们存储在 Web 根目录之外的文件中。
include('../otherDirectory/configfile.conf')
吗?
对于极其安全的系统,我们在配置文件中加密数据库密码(该文件本身由系统管理员保护)。在应用程序/服务器启动时,应用程序会提示系统管理员输入解密密钥。然后从配置文件中读取数据库密码,解密并存储在内存中以供将来使用。仍然不是 100% 安全,因为它存储在解密后的内存中,但在某些时候你必须称它为“足够安全”!
这个解决方案是通用的,因为它对开源和闭源应用程序都很有用。
为您的应用程序创建一个操作系统用户。请参阅 http://en.wikipedia.org/wiki/Principle_of_least_privilege 为该用户创建一个(非会话)操作系统环境变量,使用密码以该用户身份运行应用程序
优点:
您不会意外地将您的密码检查到源代码管理中,因为您不会意外地搞砸文件权限。嗯,你可以,但它不会影响这一点。只能由 root 或该用户读取。无论如何,Root 都可以读取您的所有文件和加密密钥。如果您使用加密,您如何安全地存储密钥? Works x-platform 确保不要将 envvar 传递给不受信任的子进程
这种方法是 Heroku 提出的,非常成功。
如果可以在存储凭据的同一文件中创建数据库连接。在连接语句中内联凭据。
mysql_connect("localhost", "me", "mypass");
否则最好在连接语句之后取消设置凭据,因为不在内存中的凭据不能是 read from memory ;)
include("/outside-webroot/db_settings.php");
mysql_connect("localhost", $db_user, $db_pass);
unset ($db_user, $db_pass);
以前我们将 DB 用户/密码存储在配置文件中,但后来进入了偏执模式——采用深度防御策略。
如果您的应用程序受到威胁,用户将拥有对您的配置文件的读取权限,因此破解者有可能读取此信息。配置文件也可能陷入版本控制,或在服务器周围复制。
我们已切换到在 Apache VirtualHost 中设置的环境变量中存储用户/密码。此配置只能由 root 读取——希望您的 Apache 用户没有以 root 身份运行。
缺点是现在密码在全局 PHP 变量中。
为了降低这种风险,我们采取了以下预防措施:
密码已加密。我们扩展 PDO 类以包含用于解密密码的逻辑。如果有人阅读了我们建立连接的代码,那么很明显连接是使用加密密码而不是密码本身建立的。
加密密码从全局变量移动到私有变量中。应用程序立即执行此操作以减少该值在全局空间中可用的窗口。
phpinfo() 被禁用。 PHPInfo 是获取所有内容(包括环境变量)概览的简单目标。
您的选择是有限的,因为您说您需要密码才能访问数据库。一种通用方法是将用户名和密码存储在单独的配置文件中,而不是主脚本中。然后确保将其存储在主网络树之外。那就是如果存在网络配置问题,导致您的 php 文件仅显示为文本而不是被执行,那么您还没有暴露密码。
除此之外,您在正确的线路上,对正在使用的帐户的访问权限最小。添加到那个
不要将用户名/密码的组合用于其他任何事情
将数据库服务器配置为仅接受来自该用户的 Web 主机的连接(如果数据库位于同一台计算机上,则 localhost 会更好)这样即使凭据被公开,除非他们具有其他访问权限,否则它们对任何人都没有用机器。
混淆密码(即使是 ROT13 也会这样做)如果某些人确实可以访问该文件,它不会进行太多防御,但至少它会阻止随意查看它。
彼得
我们以这种方式解决了它:
在服务器上使用 memcache,并打开来自其他密码服务器的连接。将密码(甚至所有已加密的 password.php 文件)和解密密钥保存到内存缓存中。该网站调用保存密码文件密码的 memcache 密钥并在内存中解密所有密码。密码服务器每 5 分钟发送一个新的加密密码文件。如果您在项目中使用加密的 password.php,则进行审核,以检查该文件是否被外部触摸或查看过。发生这种情况时,您可以自动清理内存,以及关闭服务器以供访问。
将数据库密码放在一个文件中,使其对提供文件的用户只读。
除非您有某种方法只允许 php 服务器进程访问数据库,否则您几乎可以做到这一点。
如果您谈论的是数据库密码,而不是来自浏览器的密码,标准做法似乎是将数据库密码放在服务器上的 PHP 配置文件中。
您只需要确保包含密码的 php 文件对其具有适当的权限。即它应该只能由网络服务器和您的用户帐户读取。
php.ini
(config) 文件(我认为这是您的文件)参考)。这不会“被 phpinfo() 读取”。
另一个技巧是使用 PHP 单独的配置文件,如下所示:
<?php exit() ?>
[...]
Plain text data including password
这不会妨碍您正确设置访问规则。但是如果您的网站被黑客入侵,“require”或“include”只会在第一行退出脚本,因此更难获取数据。
尽管如此,永远不要将配置文件放在可以通过 Web 访问的目录中。您应该有一个“Web”文件夹,其中包含您的控制器代码、css、图片和 js。就这样。其他任何内容都在脱机文件夹中。
require
/include
但如何阻止做 fopen
?
只需将其放入某个配置文件中就是通常的做法。只要确保你:
禁止从网络外的任何服务器访问数据库,注意不要意外向用户显示密码(在错误消息中,或通过 PHP 文件意外作为 HTML 提供,等等。)
最好的方法是根本不存储密码!例如,如果您在 Windows 系统上并连接到 SQL Server,则可以使用集成身份验证使用当前进程的身份连接到数据库而无需密码。
如果您确实需要使用密码连接,请先对其进行加密,使用强加密(例如使用 AES-256,然后保护加密密钥,或使用非对称加密并让操作系统保护证书),然后将其存储在具有强 ACL 的配置文件(在 web 目录之外)。
实际上,最佳做法是将数据库凭据存储在环境变量中,因为:
这些凭据取决于环境,这意味着您在 dev/prod 中不会拥有相同的凭据。将它们存储在所有环境的同一个文件中是错误的。
凭据与业务逻辑无关,这意味着登录名和密码与您的代码无关。
您可以在不创建任何业务代码类文件的情况下设置环境变量,这意味着您永远不会犯将凭证文件添加到 Git 中的提交的错误。
环境变量是超全局变量:您可以在代码中的任何地方使用它们,而无需包含任何文件。
如何使用它们?
使用 $_ENV 数组:设置:$_ENV['MYVAR'] = $myvar 获取:echo $_ENV["MYVAR"]
设置:$_ENV['MYVAR'] = $myvar
获取:回声 $_ENV["MYVAR"]
使用 php 函数:使用 putenv 函数进行设置 - putenv("MYVAR=$myvar");使用 getenv 函数 - getenv('MYVAR');
使用 putenv 函数进行设置 - putenv("MYVAR=$myvar");
使用 getenv 函数 - getenv('MYVAR');
在 vhosts 文件和 .htaccess 中,但不建议这样做,因为它在另一个文件中,并且无法通过这种方式解决问题。
您可以轻松地删除一个包含所有环境变量的文件,例如 envvars.php,然后执行它(php envvars.php
)并删除它。这有点老派,但它仍然有效,并且您在服务器中没有任何包含您的凭据的文件,您的代码中也没有凭据。由于它有点费力,框架做得更好。
Symfony 的示例(好吧,不仅仅是 PHP) 现代框架如 Symfony 建议使用环境变量,并将它们存储在 .env 未提交的文件中或直接存储在命令行中,这意味着您可以这样做:
使用 CLI:symfony var:set FOO=bar --env-level
使用 .env 或 .env.local : FOO="bar"
文档: