如何在PHP中保护数据库密码?
当PHP应用程序进行数据库连接时,通常需要传递login名和密码。 如果我为我的应用程序使用了一个最小权限login,那么PHP需要知道login名和密码。 什么是保护密码的最佳方式? 这似乎只是写在PHP代码是不是一个好主意。
有几个人误解这是一个关于如何将密码存储在数据库中的问题。 那是错的。 这是关于如何存储让你到数据库的密码。
通常的解决scheme是将密码从源代码移出到configuration文件中。 然后离开pipe理和保护该configuration文件到您的系统pipe理员。 这样开发人员不需要知道任何有关生产密码的信息,并且在源代码pipe理中没有密码logging。
如果您在别人的服务器上托pipe,并且没有访问webroot的权限,则可以始终将密码和/或数据库连接置于文件中,然后使用.htaccesslocking该文件:
<files mypasswdfile> order allow,deny deny from all </files>
将它们存储在Web根目录外的文件中。
对于非常安全的系统,我们在configuration文件(它本身由系统pipe理员保护)中encryption数据库密码。 在应用程序/服务器启动时,应用程序会提示系统pipe理员input解密密钥。 然后从configuration文件中读取数据库密码,解密并存储在内存中以供将来使用。 仍然不是100%安全的,因为它被存储在内存中解密,但你必须在某个时候称它为'安全'!
最安全的方法是根本没有在您的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"));
这个解决scheme是通用的,因为它对于开源和闭源应用程序都是有用的。
- 为您的应用程序创build一个OS用户。 请参阅http://en.wikipedia.org/wiki/Principle_of_least_privilege
- 使用密码为该用户创build(非会话)OS环境variables
- 以该用户身份运行该应用程序
优点:
- 您不会无意中将您的密码检入源代码pipe理,因为您不能
- 你不会不小心搞砸了文件权限。 那么,你可以,但不会影响到这一点。
- 只能由root或该用户读取。 Root可以读取所有文件和encryption密钥。
- 如果你使用encryption,你如何安全地存储密钥?
- 作品x平台
- 一定不要将envvar传递给不可信的subprocess
Herokubuild议这个方法非常成功。
如果可以在存储凭据的相同文件中创build数据库连接。 在连接语句中内联凭证。
mysql_connect("localhost", "me", "mypass");
否则,最好在连接语句之后取消设置凭证,因为不在内存中的凭证不能从内存读取 ;)
include("/outside-webroot/db_settings.php"); mysql_connect("localhost", $db_user, $db_pass); unset ($db_user, $db_pass);
你的select是有限的,因为你说你需要密码来访问数据库。 一种通用的方法是将用户名和密码存储在单独的configuration文件中而不是主脚本中。 那么一定要把它存储在主Web树的外面。 这是如果有一个Webconfiguration问题,让您的PHP文件只是简单地显示为文本而不是执行,你没有暴露的密码。
除此之外,您正在使用正确的线路,只需最小的访问权限。 除此之外
- 不要使用用户名/密码的组合
- 将数据库服务器configuration为只接受来自该用户的Web主机的连接(如果数据库在同一台计算机上,则本地主机甚至更好)这样,即使凭据被公开,对任何人都是无用的,除非他们有其他访问机。
- 混淆密码(即使是ROT13也会这样做),如果有人能够访问这个文件,它不会提供很多的防御措施,但是至less会阻止它的随意查看。
彼得
如果您使用的是PostgreSQL,那么它会自动查找~/.pgpass
中的密码。 有关更多信息,请参阅手册 。
将数据库密码放在一个文件中,使其成为只读文件的用户。
除非你有一些只允许php服务器进程访问数据库的方法,否则这几乎是你所能做的。
如果您正在讨论数据库密码,而不是来自浏览器的密码,那么标准做法似乎是将数据库密码放在服务器上的PHPconfiguration文件中。
你只需要确保包含密码的php文件具有适当的权限就可以了。 也就是说,只能通过Web服务器和用户帐户来阅读。
我认为OP意味着数据库密码。
除非有人通过FTP或SSH访问您的服务器(在这种情况下,您已经错过了),我不会担心在PHP文件中以明文存储密码。 我见过的大多数PHP应用程序都是这样做的,例如phpbb。
最好的方法是根本不存储密码!
例如,如果您在Windows系统上并连接到SQL Server,那么可以使用集成身份validation来使用当前进程的身份而不用密码连接到数据库。
如果您确实需要使用密码进行连接,请先使用高度encryption(例如,使用AES-256,然后保护encryption密钥或使用非对称encryption并使操作系统保护证书)对其进行encryption,然后将其存储在configuration文件(在Web目录之外),使用强大的ACL 。
另一个技巧是使用一个PHP单独的configuration文件,如下所示:
<?php exit() ?> [...] Plain text data including password
这并不妨碍您正确设置访问规则。 但是如果你的网站被黑客攻击,那么“require”或者“include”就会在第一行退出脚本,所以更难获取数据。
不过,不要让configuration文件放在可以通过networking访问的目录中。 你应该有一个包含你的控制器代码,CSS,图片和JS的“Web”文件夹。 就这样。 其他任何事情都在脱机文件夹中。
把它放在一个configuration文件的地方是通常的做法。 只要确保你:
- 禁止从networking外的任何服务器访问数据库,
- 注意不要意外地向用户显示密码(在错误信息中,或通过PHP文件意外地作为HTML等等)。
我们用这种方式解决了这个问题:
- 在服务器上使用memcache,从其他密码服务器打开连接。
- 保存到memcache的密码(甚至是encryption的所有password.php文件)加上解密密钥。
- 该网站调用持有密码文件密码的memcache密钥,并在内存中解密所有的密码。
- 密码服务器每5分钟发送一个新的encryption密码文件。
- 如果您在项目中使用encryption的password.php,则需要进行审计,检查是否外部触摸了此文件或查看了该文件。 发生这种情况时,您可以自动清理内存,并closures服务器以进行访问。
以前我们在configuration文件中存储了数据库用户/密码,但是之后又出现了偏执模式 – 采用深度防御策略。
如果您的应用程序遭到破坏,用户将拥有对您configuration文件的读取访问权限,所以攻击者有可能读取这些信息。 configuration文件也可能受到版本控制,或者在服务器周围复制。
我们已经切换到在Apache VirtualHost中设置的环境variables中存储用户/密码。 这个configuration只能由root读取 – 希望你的Apache用户不能以root身份运行。
与此同时,现在密码是全局PHPvariables。
为了减轻这种风险,我们有以下的预防措施:
- 密码被encryption。 我们扩展PDO类以包含解密密码的逻辑。 如果有人在我们build立连接的地方读取代码,那么使用encryption的密码而不是密码本身build立连接并不明显。
- encryption的密码从全局variables移动到私有variables中应用程序会立即执行此操作,以减less全局空间中可用值的窗口。
-
phpinfo()
被禁用。 PHPInfo是一个简单的目标,可以概括一切,包括环境variables。