Commit a68c0462 authored by alexpott's avatar alexpott
Browse files

Issue #2388255 by dawehner, hussainweb, pwolanin: Limit PDO MySQL to executing...

Issue #2388255 by dawehner, hussainweb, pwolanin: Limit PDO MySQL to executing single statements if PHP supports it
parent 3c0892d0
...@@ -18,7 +18,8 @@ Drupal requires: ...@@ -18,7 +18,8 @@ Drupal requires:
- A web server with PHP support, for example: - A web server with PHP support, for example:
- Apache 2.0 (or greater) (http://httpd.apache.org/). - Apache 2.0 (or greater) (http://httpd.apache.org/).
- Nginx 1.1 (or greater) (http://nginx.com/). - Nginx 1.1 (or greater) (http://nginx.com/).
- PHP 5.4.5 (or greater) (http://php.net/). - PHP 5.4.5 (or greater) (http://php.net/). For better security support its
recommended to update to at least 5.5.21 or 5.6.5.
- One of the following databases: - One of the following databases:
- MySQL 5.0.15 (or greater) (http://www.mysql.com/). - MySQL 5.0.15 (or greater) (http://www.mysql.com/).
- MariaDB 5.1.44 (or greater) (https://mariadb.org/). MariaDB is a fully - MariaDB 5.1.44 (or greater) (https://mariadb.org/). MariaDB is a fully
...@@ -62,6 +63,10 @@ OPTIONAL SERVER REQUIREMENTS ...@@ -62,6 +63,10 @@ OPTIONAL SERVER REQUIREMENTS
configuration allows the web server to initiate outbound connections. Most web configuration allows the web server to initiate outbound connections. Most web
hosting setups allow this. hosting setups allow this.
- PHP 5.5.21 provides features for improved security when used with MySQL. While
this is not required, it is highly encouraged to use PHP 5.5.21 or 5.6.5 and
above.
INSTALLATION INSTALLATION
------------ ------------
......
...@@ -925,6 +925,8 @@ function drupal_check_profile($profile, array $install_state) { ...@@ -925,6 +925,8 @@ function drupal_check_profile($profile, array $install_state) {
foreach ($info['dependencies'] as $module) { foreach ($info['dependencies'] as $module) {
module_load_install($module); module_load_install($module);
$function = $module . '_requirements'; $function = $module . '_requirements';
drupal_classloader_register($module, drupal_get_path('module', $module));
if (function_exists($function)) { if (function_exists($function)) {
$requirements = array_merge($requirements, $function('install')); $requirements = array_merge($requirements, $function('install'));
} }
......
...@@ -83,6 +83,11 @@ public static function open(array &$connection_options = array()) { ...@@ -83,6 +83,11 @@ public static function open(array &$connection_options = array()) {
// Because MySQL's prepared statements skip the query cache, because it's dumb. // Because MySQL's prepared statements skip the query cache, because it's dumb.
\PDO::ATTR_EMULATE_PREPARES => TRUE, \PDO::ATTR_EMULATE_PREPARES => TRUE,
); );
if (defined('\PDO::MYSQL_ATTR_MULTI_STATEMENTS')) {
// An added connection option in PHP 5.5.21 to optionally limit SQL to a
// single statement like mysqli.
$connection_options['pdo'] += [\PDO::MYSQL_ATTR_MULTI_STATEMENTS => FALSE];
}
$pdo = new \PDO($dsn, $connection_options['username'], $connection_options['password'], $connection_options['pdo']); $pdo = new \PDO($dsn, $connection_options['username'], $connection_options['password'], $connection_options['pdo']);
...@@ -110,8 +115,10 @@ public static function open(array &$connection_options = array()) { ...@@ -110,8 +115,10 @@ public static function open(array &$connection_options = array()) {
$connection_options['init_commands'] += array( $connection_options['init_commands'] += array(
'sql_mode' => "SET sql_mode = 'ANSI,STRICT_TRANS_TABLES,STRICT_ALL_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER'", 'sql_mode' => "SET sql_mode = 'ANSI,STRICT_TRANS_TABLES,STRICT_ALL_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER'",
); );
// Set connection options. // Execute initial commands.
$pdo->exec(implode('; ', $connection_options['init_commands'])); foreach ($connection_options['init_commands'] as $sql) {
$pdo->exec($sql);
}
return $pdo; return $pdo;
} }
......
<?php
/**
* @file
* Contains \Drupal\system\SystemRequirements.
*/
namespace Drupal\system;
/**
* Class for helper methods used for the system requirements.
*/
class SystemRequirements {
/**
* Determines whether the passed in PHP version disallows multiple statements.
*
* @param string $phpversion
*
* @return bool
*/
public static function phpVersionWithPdoDisallowMultipleStatements($phpversion) {
// PDO::MYSQL_ATTR_MULTI_STATEMENTS was introduced in PHP versions 5.5.21
// and 5.6.5.
return (version_compare($phpversion, '5.5.21', '>=') && version_compare($phpversion, '5.6.0', '<'))
|| version_compare($phpversion, '5.6.5', '>=');
}
}
...@@ -118,4 +118,22 @@ function testConnectionOptions() { ...@@ -118,4 +118,22 @@ function testConnectionOptions() {
$this->assertNotEqual($connection_info['default']['database'], $connectionOptions['database'], 'The test connection info database does not match the current connection options database.'); $this->assertNotEqual($connection_info['default']['database'], $connectionOptions['database'], 'The test connection info database does not match the current connection options database.');
} }
/**
* Ensure that you cannot execute multiple statements on phpversion() > 5.5.21 or > 5.6.5.
*/
public function testMultipleStatementsForNewPhp() {
if (!defined('\PDO::MYSQL_ATTR_MULTI_STATEMENTS')) {
return;
}
$db = Database::getConnection('default', 'default');
try {
$db->query('SELECT * FROM {test}; SELECT * FROM {test_people}')->execute();
$this->fail('NO PDO exception thrown for multiple statements.');
}
catch (\Exception $e) {
$this->pass('PDO exception thrown for multiple statements.');
}
}
} }
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
use Drupal\Core\Site\Settings; use Drupal\Core\Site\Settings;
use Drupal\Core\StreamWrapper\PrivateStream; use Drupal\Core\StreamWrapper\PrivateStream;
use Drupal\Core\StreamWrapper\PublicStream; use Drupal\Core\StreamWrapper\PublicStream;
use Drupal\system\SystemRequirements;
/** /**
* Implements hook_requirements(). * Implements hook_requirements().
...@@ -80,6 +81,17 @@ function system_requirements($phase) { ...@@ -80,6 +81,17 @@ function system_requirements($phase) {
return $requirements; return $requirements;
} }
// Suggest to update to at least 5.5.21 or 5.6.5 for disabling multiple
// statements.
if (($phase === 'install' || \Drupal::database()->driver() === 'mysql') && !SystemRequirements::phpVersionWithPdoDisallowMultipleStatements($phpversion)) {
$requirements['php'] = array(
'title' => t('PHP (multiple statement disabling)'),
'value' => $phpversion,
'description' => t('PHP versions higher than 5.6.5 or 5.5.21 provide built-in SQL injection protection for mysql databases. It is recommended to update.'),
'severity' => REQUIREMENT_INFO,
);
}
// Test for PHP extensions. // Test for PHP extensions.
$requirements['php_extensions'] = array( $requirements['php_extensions'] = array(
'title' => t('PHP extensions'), 'title' => t('PHP extensions'),
......
<?php
/**
* @file
* Contains \Drupal\Tests\system\Unit\SystemRequirementsTest.
*/
namespace Drupal\Tests\system\Unit;
use Drupal\system\SystemRequirements;
use Drupal\Tests\UnitTestCase;
/**
* @coversDefaultClass Drupal\system\SystemRequirements
*/
class SystemRequirementsTest extends UnitTestCase {
/**
* @dataProvider providerTestPhpVersionWithPdoDisallowMultipleStatements
*/
public function testPhpVersionWithPdoDisallowMultipleStatements($version, $expected) {
$this->assertEquals($expected, SystemRequirements::phpVersionWithPdoDisallowMultipleStatements($version));
}
public function providerTestPhpVersionWithPdoDisallowMultipleStatements() {
$data = [];
$data[] = ['5.4.2', FALSE];
$data[] = ['5.4.21', FALSE];
$data[] = ['5.5.9', FALSE];
$data[] = ['5.5.20', FALSE];
$data[] = ['5.5.21', TRUE];
$data[] = ['5.5.30', TRUE];
$data[] = ['5.6.2', FALSE];
$data[] = ['5.6.5', TRUE];
$data[] = ['5.5.21', TRUE];
return $data;
}
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment