Подтвердить что ты не робот

Почему PDO печатает мой пароль при сбое соединения?

У меня есть простой сайт, на котором я устанавливаю соединение с сервером Mysql с использованием PDO.

$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, и поэтому мой вопрос: что я должен сделать, чтобы считать безопасным? Как установить соединение безопасным способом? Существуют ли другие известные дыры в безопасности, подобные этой, о которой я должен знать?

4b9b3361

Ответ 1

Вы должны иметь display_errors = off в вашем PHP.ini в любом случае, чтобы избежать этой проблемы. Ошибки, которые раскрывают такие данные, поступают из многих мест, в дополнение к PDO.

Да, вы также должны иметь его в блоке try/catch.

Вы также можете $pdo->setAttribute(PDO::ERRMODE_SILENT), но тогда вам нужно вручную проверять коды ошибок, а не использовать блок try/catch. См. http://php.net/manual/en/pdo.setattribute.php для получения дополнительных констант ошибок.

Ответ 2

Хорошо, это заставило меня немного хихикать, использование отчетов об ошибках предназначено для целей отладки, это позволяет быстро находить и исправлять проблемы.

Когда вы находитесь в живой среде, ваш сервер должен быть настроен только для внутреннего ведения журнала, а не для прямого вывода, поэтому в основном вам нужно будет отключить вывод ошибок в вашем php.ini.

display_errors = Off

Но пока вы находитесь в своей тестовой среде, этот стек - это просто инструмент, который поможет вам и настраивается.

При возникновении ошибок в живой среде они будут регистрироваться, поэтому вы всегда должны проверять свои файлы журналов, а затем исправлять их.

Люди могут указывать, что вы можете управлять ошибками в своем PHP-приложении, но по личным предпочтениям я думаю, что это неправильный путь для этого, настройка INI и файлов конфигурации для вашего веб-сервера и MySQL/MsSQL приведет к большему количеству острое управление.

Если ваше приложение является общедоступным приложением, тогда было бы неплохо обрабатывать ошибки в приложении, так как большой процент клиентов может находиться на общем хостинге и не иметь полного доступа к конфигурациям сервера.

Ответ 3

Простой обходной путь, чтобы поймать PDOException, созданный конструктором PDO:

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');
}

Ответ 4

Мы используем закодированное имя пользователя и пароли и декодируем их в конструкторе 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;
        }
    }