Commit a68c0462 authored by alexpott's avatar alexpott

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:
- A web server with PHP support, for example:
- Apache 2.0 (or greater) (http://httpd.apache.org/).
- 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:
- MySQL 5.0.15 (or greater) (http://www.mysql.com/).
- MariaDB 5.1.44 (or greater) (https://mariadb.org/). MariaDB is a fully
......@@ -62,6 +63,10 @@ OPTIONAL SERVER REQUIREMENTS
configuration allows the web server to initiate outbound connections. Most web
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
------------
......
......@@ -925,6 +925,8 @@ function drupal_check_profile($profile, array $install_state) {
foreach ($info['dependencies'] as $module) {
module_load_install($module);
$function = $module . '_requirements';
drupal_classloader_register($module, drupal_get_path('module', $module));
if (function_exists($function)) {
$requirements = array_merge($requirements, $function('install'));
}
......
......@@ -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.
\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']);
......@@ -110,8 +115,10 @@ public static function open(array &$connection_options = 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'",
);
// Set connection options.
$pdo->exec(implode('; ', $connection_options['init_commands']));
// Execute initial commands.
foreach ($connection_options['init_commands'] as $sql) {
$pdo->exec($sql);
}
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() {
$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 @@
use Drupal\Core\Site\Settings;
use Drupal\Core\StreamWrapper\PrivateStream;
use Drupal\Core\StreamWrapper\PublicStream;
use Drupal\system\SystemRequirements;
/**
* Implements hook_requirements().
......@@ -80,6 +81,17 @@ function system_requirements($phase) {
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.
$requirements['php_extensions'] = array(
'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