为什么连接失败时PDO会打印我的密码?

我有一个简单的网站,我使用PDObuild立与Mysql服务器的连接。

$dbh = new PDO('mysql:host=localhost;dbname=DB;port=3306', 'USER', 'SECRET',array(PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8")); 

我在我的网站上有一些stream量,并达到了服务器连接限制,网站抛出这个错误,我的PLAIN密码!

致命错误:带有消息'SQLSTATE的未捕获exception'PDOException'[08004] [1040] /home/domain/html/index.php:xxx中的连接太多堆栈跟踪:#0 /home/domain/html/index.php (64):PDO – > __ construct('mysql:host = loca …','USER','SECRET',Array)#1 {main}在第64行抛出/home/domain/html/index.php

具有讽刺意味的是,为了安全起见,我转而使用PDO,所以这真的让我感到震惊,因为这个确切的错误是你可以在大多数使用简单http泛滥的站点上很容易引起的。

我现在已经把我的连接包装在try / catch块中,但是我认为这是灾难性的!

我是PDO的新手,所以我的问题是:为了保证安全,我该怎么做? 如何以安全的方式build立连接? 还有其他已知的安全漏洞,我必须注意这个吗?

你应该在你的PHP.ini中有display_errors = off来避免这个问题。 揭示这些细节的错误来自许多地方,除了PDO之外。

是的,你也应该在try / catch块中。

您也可以$pdo->setAttribute(PDO::ERRMODE_SILENT) ,但是您需要手动检查错误代码,而不是使用try / catch块。 看到http://php.net/manual/en/pdo.setattribute.php更多的错误常量。;

好吧,这使我咯咯一笑,使用错误报告是为了debugging的目的,它可以让你快速find并解决问题。

当你在一个实时环境中时,你的服务器应该只configuration为内部日志logging,而不是直接输出,所以基本上你需要closuresphp.ini的错误输出。

 display_errors = Off 

但是,当你处于testing环境中时,这个堆栈只是一个帮助你的工具,而且是可configuration的。

当活动环境中发生错误时,他们将被logging,所以你应该总是检查你的日志文件,然后相应地修复。

人们可能会指定你可以pipe理你的PHP应用程序中的错误,但个人喜好,我认为这是错误的方式去做,为你的Web服务器和MySQL / MsSQLconfigurationINI和configuration文件将导致更严格的pipe理。

如果您的应用程序是公共应用程序,那么在应用程序中处理错误也是一个好主意,因为大部分客户端可能在共享主机上,并且不能完全访问服务器configuration。

它捕捉PDO构造函数引发的PDOException的简单的解决方法:

 try { $dbh = new PDO('mysql:host=localhost;dbname=DB;port=3306', 'USER', 'SECRET',array(PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8")); } catch (PDOException $e) { throw new Exception('Could not connect to database'); } 

我们使用经过编码的用户名和密码,并在PDO构造函数中对其进行解码,然后我们捕获PDOException并抛出一个新的PDOException,其旧消息的消息,以便跟踪将只显示编码的用户名和密码。

一个好的PHPencryption库是:defuse / php-encryption

https://github.com/defuse/php-encryption

示例代码:

 <?php class myPDOWrapper extends PDO { public function __construct(string $dns, string $encodedUser, string $encodedPassword) { try { parent::__construct($dns, $this->decodeFunction($encodedUser), $this->decodeFunction($encodedPassword), [ PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, ] ); } catch (PDOException $exception) { throw new PDOException($exception->getMessage()); } } private function decodeFunction(string $encoded): string { return \Defuse\Crypto\Crypto::decrypt($encoded, $this->decodeKey()); } private function decodeKey(): \Defuse\Crypto\Key { static $key = null; if(null === $key) { $key = \Defuse\Crypto\Key::loadFromAsciiSafeString(getenv('MY_PDO_DECODE_KEY')); } return $key; } }