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

时间:2011-06-23 13:43:38

标签: php mysql security connection pdo

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

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

我的网站上有一些流量,并且达到了服务器连接限制,并且网站引发了此错误,其中包含我的PLAIN密码!

  

致命错误:未捕获的异常   带有消息的'PDOException'   'SQLSTATE [08004] [1040]太多了   连接'   /home/domain/html/index.php:xxx   堆栈跟踪:#0   /home/domain/html/index.php(64):   PDO-> __构建体( 'MySQL的:主机=轨迹...',   'USER','SECRET',Array)#1   抛出了{main}   /home/domain/html/index.php on   第64行

具有讽刺意味的是,我出于安全原因切换到了PDO,所以这让我很震惊,因为这个确切的错误是你可以在大多数使用简单的http泛滥的网站上轻易引起的。

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

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

4 个答案:

答案 0 :(得分:20)

无论如何,您的PHP.ini应该有display_errors = off以避免此问题。除了PDO之外,揭示这些细节的错误来自许多地方。

是的,您还应该在try / catch块中使用它。

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

答案 1 :(得分:14)

简单的解决方法是捕获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($e->getMessage());
}

答案 2 :(得分:7)

好的,这让我有点傻笑,错误报告的使用是出于调试目的,它可以让你快速找到并解决问题。

当您处于实时环境中时,您的服务器应仅配置为内部日志记录,而不是直接输出,因此基本上您需要关闭php.ini中的错误输出。

display_errors = Off

但是当你在测试环境中时,这个堆栈只是一个可以帮助你的工具,并且是可配置的。

如果在实时环境中发生错误,则会记录这些错误,因此您应始终检查日志文件,然后进行相应的修复。

人们可能会指定您可以管理PHP应用程序中的错误,但是根据个人喜好,我认为这是错误的方法,为您的Web服务器和MySQL / MsSQL配置INI和配置文件将导致更多急性管理。

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

答案 3 :(得分:2)

我们使用编码的用户名和密码,并解码PDO构造函数中的那些,然后我们捕获PDOException并抛出一个新的PDOException,其旧的异常是它的消息,这样跟踪将只显示编码的用户名和密码。

PHP的一个很好的加密库是: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;
        }
    }