Moved from security bug report: "This should be a pubic hardening since there is no direct exploit"
Risk: If someone has
* At least read-only access to wherever php is writing its error logs,
* And can cause Drupal to fail to connect to the database (or can just wait for a network event that causes this),
Then they can find the username and password Drupal is using to connect.
This is with Drupal 8.6.16
I’m fairly certain this is in just Drupal Core, but haven’t actually tried it with just a base install.
If Drupal fails to connect to the database, it logs to the standard error log: (sanitized our database and password info with XXXX)
PDOException: SQLSTATE[HY000] [2002] php_network_getaddresses: getaddrinfo failed: Name or
service not known in /var/www/html/core/lib/Drupal/Component/DependencyInjection/PhpArrayContainer.php on line 79 #0 /var/www/html/core/lib/Drupal/Core/Database/Driver/mysql/Connection.php(420): PDO->__construct('mysql:host=va-v...', 'XXXdevweb', 'XXXXXXXXXXXX', Array)\n#1 /var/www/html/core/lib/Drupal/Core/Database/Database.php(371): Drupal\\Core\\Database\\Driver\\mysql\\Connection::open(Array)\n#2 /var/www/html/core/lib/Drupal/Core/Database/Database.php(166): Drupal\\Core\\Database\\Database::openConnection('default', 'default')\n#3 [internal function]: Drupal\\Core\\Database\\Database::getConnection('default')\n#4 /var/www/html/core/lib/Drupal/Component/DependencyInjection/PhpArrayContainer.php(79): call_user_func_array('Drupal\\\\Core\\\\Dat...', Array)\n#5 /var/www/html/core/lib/Drupal/Component/DependencyInjection/Container.php(171): Drupal\\Component\\DependencyInjection\\PhpArrayContainer->createService(Array, 'database')\n#6 /var/www/html/core/lib/Drupal/Component/DependencyInjection/PhpArrayContainer.php(260): Drupal\\Component\\DependencyInjection\\Container->get('database', 1)\n#7 /var/www/html/core/lib/Drupal/Component/DependencyInjection/PhpArrayContainer.php(62): Drupal\\Component\\DependencyInjection\\PhpArrayContainer->resolveServicesAndParameters(Array)\n#8 /var/www/html/core/lib/Drupal/Component/DependencyInjection/Container.php(171): Drupal\\Component\\DependencyInjection\\PhpArrayContainer->createService(Array, 'cache.container')\n#9 /var/www/html/core/lib/Drupal/Core/DrupalKernel.php(543): Drupal\\Component\\DependencyInjection\\Container->get('cache.container')\n#10 /var/www/html/core/lib/Drupal/Core/DrupalKernel.php(904): Drupal\\Core\\DrupalKernel->getCachedContainerDefinition()\n#11 /var/www/html/core/lib/Drupal/Core/DrupalKernel.php(476): Drupal\\Core\\DrupalKernel->initializeContainer()\n#12 /var/www/html/core/lib/Drupal/Core/DrupalKernel.php(692): Drupal\\Core\\DrupalKernel->boot()\n#13 /var/www/html/index.php(19): Drupal\\Core\\DrupalKernel->handle(Object(Symfony\\Component\\HttpFoundation\\Request))\n#14 {main}
Which includes both the username (XXXdevweb) and password (XXXXXXXXXXXX) in plain text.
The problem is in core/lib/Drupal/Core/Database/Driver/mysql/Connection.php in the catch for line 419. The default error handler prints the sensitive information.
try {
$pdo = new \PDO($dsn, $connection_options['username'], $connection_options['password'], $connection_options['pdo']);
}
catch (\PDOException $e) {
if ($e->getCode() == static::DATABASE_NOT_FOUND) {
throw new DatabaseNotFoundException($e->getMessage(), $e->getCode(), $e);
}
if ($e->getCode() == static::ACCESS_DENIED) {
throw new DatabaseAccessDeniedException($e->getMessage(), $e->getCode(), $e);
}
throw $e;
}
The below fixes the issue, but uses DatabaseAccessDeniedException() incorrectly, and shouldn’t be used, but a new exception handler like it would probably be the correct solution. I just don’t have the time to dig into things to identify what’s the correct resolution, and this works well enough for us.
diff a/core/lib/Drupal/Core/Database/Driver/mysql/Connection.php b/core/lib/Drupal/Core/Database/Driver/mysql/Connection.php
429c429
> throw $e;
---
< throw new DatabaseAccessDeniedException($e->getMessage(), $e->getCode(), $e);
--
Thanks,
Billy Arnold
Senior Systems Administrator
Virginia Interactive / VI