PHP MySQL через SSL. Сертификат партнера не совпал

Я пытаюсь использовать Google Cloud SQL через SSL из экземпляра GCE (Google Compute Engine). Моя проблема в том, что я не могу подключиться к экземпляру Cloud SQL через SSL.

Команда mysql работает нормально. Я могу подключиться к экземпляру Cloud SQL с файлами сертификации.

mysql -uroot -p -h [IP Address] --ssl-ca=/home/user/.cert/server-ca.pem --ssl-cert=/home/user/.cert/client-cert.pem  --ssl-key=/home/user/.cert/client-key.pem

Тем не менее, я получил предупреждение и фатальную ошибку, как и при доступе к PHP-программе.

<?php
$pdo = new PDO('mysql:host=[IP Address];dbname=testdb', 'root', 'test', array(
    PDO::MYSQL_ATTR_SSL_KEY    =>'/home/user/.cert/client-key.pem',
    PDO::MYSQL_ATTR_SSL_CERT=>'/home/user/.cert/client-cert.pem',
    PDO::MYSQL_ATTR_SSL_CA    =>'/home/user/.cert/server-ca.pem'
    )
);
$stmt = $pdo->query("SHOW TABLES;");
$row = $stmt->fetch(PDO::FETCH_ASSOC);
print_r($row);
?> 

PHP Warning:  PDO::__construct(): Peer certificate CN='[GCP project name]:[Cloud SQL instance name]' did not match expected CN='[IP Address]' in /tmp/mysql.php on line 7
Fatal error: Uncaught exception 'PDOException' with message 'SQLSTATE[HY000] [2002] ' in /tmp/mysql.php on line 7

У меня такая же ошибка, когда я использовал mysqli.

$mysqli = mysqli_init();
mysqli_options($mysqli, MYSQLI_OPT_SSL_VERIFY_SERVER_CERT, true);

$mysqli->ssl_set('/home/user/.cert/client-key.pem',
                 '/home/user/.cert/client-cert.pem',
                 '/home/user/.cert/server-ca.pem',
                  NULL,NULL);

$mysqli->real_connect('[IP Address]', 'root', 'test', 'testdb', 3306, NULL, MYSQLI_CLIENT_SSL);

PHP Warning:  mysqli::real_connect(): Peer certificate CN='[GCP project name]:[Cloud SQL instance name]' did not match expected CN='[IP Address]' in /tmp/mysql3.php on line 30
Warning: mysqli::real_connect(): (HY000/2002):  in /tmp/mysql3.php on line 30

Этот вопрос имеет отношение к моему делу, но ответа пока нет. SSL-самоподписанные сертификаты для подключения к Mysql с PHP

Кто-нибудь знает о решениях?


Обновление 1

Сообщается об ошибке. https://bugs.php.net/bug.php?id=71003

Очень похожий вопрос здесь. Google Cloud SQL SSL отказывает проверку сертификата одноранговой сети

Моя версия PHP - 5.6.14. Я буду обновлять до 5.6.16, чтобы использовать MYSQLI_CLIENT_SSL_DONT_VERIFY_SERVER_CERT.


Обновление 2

Исправлено, когда я использую mysqli

То, что я сделал, было следующим:

1 Я обновил свой PHP до 5.6.20

sudo apt-get install php5

2 Я помещаю этот параметр MYSQLI_CLIENT_SSL_DONT_VERIFY_SERVER_CERT.

$mysqli->real_connect('[IP Address]', 'root', 'test', 'testdb', 3306, NULL, MYSQLI_CLIENT_SSL_DONT_VERIFY_SERVER_CERT);

Мое приложение использует как mysqli, так и PDO по некоторым причинам. Теперь я ищу решение для PDO.


Обновление 3

Этот отчет об ошибках показывает пример PDO. Звуки еще не исправлены.

https://bugs.php.net/bug.php?id=71845

Это также связано. https://groups.google.com/forum/?utm_medium=email&utm_source=footer#!msg/google-cloud-sql-discuss/4HNvmq7MpU4/kuSjhkS2AwAJ

Насколько я понимаю, для PDO невозможно решить проблему.


Обновление 4

Некоторые люди обвиняют дизайн Google в названиях CN (я согласен с ними на самом деле..)

В худшем случае вы, ребята, используете невозможные имена CN (:). Если бы CN был без двоеточия, возможно, я могу сопоставить ip и CN в файле моих хостов, чтобы при проверке проверки сверстников он мог пройти. С двоеточием, php думает, является хостом и является портом

и сотрудники Google? понять проблему.

Я понимаю, что текущая ситуация при подключении по IP не идеальна.

Но, похоже, они предоставляют решение под названием "прокси".

https://groups.google.com/forum/#!topic/google-cloud-sql-discuss/gAzsuCzPlaU

Я использую второе поколение Cloud SQL, а в моих приложениях размещен GCE. Поэтому я думаю, что могу использовать прокси-путь. Я попробую сейчас.


Обновление 5

Установите прокси-доступ. Решил как PDO, так и mysqli-доступ.

Установите прокси-сервер на Ubuntu

$ wget https://dl.google.com/cloudsql/cloud_sql_proxy.linux.amd64
$ mv cloud_sql_proxy.linux.amd64 cloud_sql_proxy
$ chmod +x cloud_sql_proxy
$ sudo mkdir /cloudsql; sudo chmod 777 /cloudsql
$ ./cloud_sql_proxy -dir=/cloudsql -instances=<project name>:us-central1:mydb 

PDO

<?php
$pdo = new pdo('mysql:unix_socket=/cloudsql/<project name>:us-central1:mydb;dbname=testdb','root','test');
$stmt = $pdo->query("SHOW TABLES;");
$row = $stmt->fetch(PDO::FETCH_ASSOC);
print_r($row);
?>

MySQLi

$mysqli = mysqli_connect('localhost', 'root', 'test', 'testdb', 3306, '/cloudsql/<project name>:us-central1');
$sql = "SELECT id FROM users";
if ($result = $mysqli->query($sql)) {
    while ($row = $result->fetch_assoc()) {
        echo $row["id"] . "\n";
    }
    $result->close();
}
$mysqli->close();

refs (японский)

http://blog.hrendoh.com/connecting-to-google-cloud-sql-using-mysql-client/ http://blog.hrendoh.com/google-appengine-php-using-cloud-sql/

Ответы

Ответ 1

Для соединений PDO, которые не используют облако Google или не могут воспользоваться прокси-решением, они исправили ошибку и теперь объединены. В настоящее время для этого существует постоянная (начиная с апреля 2017 года):

PDO::MYSQL_ATTR_SSL_VERIFY_SERVER_CERT => false,

http://git.php.net/?p=php-src.git;a=commit;h=247ce052cd0fc7d0d8ea1a0e7ea2075e9601766a

Надеюсь это поможет.

Ответ 2

Короче говоря, используйте Cloud SQL Proxy, если вам нужен доступ как из PDO, так и из mysqli. У вас нет выбора.

https://cloud.google.com/sql/docs/sql-proxy

Ответ 3

Для mysqli добавление:

MYSQLI_CLIENT_SSL_DONT_VERIFY_SERVER_CERT

to real_connect() решил мой экземпляр этой проблемы.

Пример (при необходимости замените хост, пользователя, пароль и базу данных):

$db_connection->real_connect('ip address or host', 'user', 'password', 'database', 3306, NULL, MYSQLI_CLIENT_SSL_DONT_VERIFY_SERVER_CERT);

Полный скрипт SSL php mysqli:

// check if openssl is enabled on server
if(!extension_loaded('openssl')) {
    throw new Exception('This app needs the Open SSL PHP extension and it is missing.');
}

// start connection
$db_connection = mysqli_init(); 

// set ssl config (update with your certs location)
$db_connection->ssl_set('/etc/my.cnf.d/certs/client-key.pem','/etc/my.cnf.d/certs/client-cert.pem', '/etc/my.cnf.d/certs/ca-cert.pem', NULL, NULL); 

// connect (update with your host, db and credentials)
$db_connection->real_connect('ip address or host', 'user', 'password', 'database', 3306, NULL, MYSQLI_CLIENT_SSL_DONT_VERIFY_SERVER_CERT);

Ответ 4

Пример в CakePHP 3.5.x + PHP 7.1.x + SQL Google Cloud + SSL

Изменить файл в: config/app.php

    ...
    ...

    /**
     * The test connection is used during the test suite.
     */
    'default' => [
        'className' => 'Cake\Database\Connection',
        'driver' => 'Cake\Database\Driver\Mysql',
        'persistent' => false,
        'host' => 'xx.xxx.xxx.xxx',
        //'port' => 'non_standard_port_number',
        'username' => 'user_name_x',
        'password' => 'pass_x',
        'database' => 'bd_name_x',
        'encoding' => 'utf8',
        'timezone' => 'UTC',
        'cacheMetadata' => true,
        'quoteIdentifiers' => false,
        'log' => false,

        'flags' => [
           PDO::MYSQL_ATTR_SSL_KEY  => CONFIG.'client-key.pem',
           PDO::MYSQL_ATTR_SSL_CERT => CONFIG.'client-cert.pem',
           PDO::MYSQL_ATTR_SSL_CA   => CONFIG.'server-ca.pem',
           PDO::MYSQL_ATTR_SSL_VERIFY_SERVER_CERT => false
        ],

        //'ssl_key' => CONFIG.'client-key.pem',
        //'ssl_cert' => CONFIG.'client-cert.pem',
        //'ssl_ca' => CONFIG.'server-ca.pem',

        //'init' => ['SET GLOBAL innodb_stats_on_metadata = 0'],
    ],
 ],
 ...
 ...

Пример PHP Pure + PDO + SSL:

$ssl_key = CONFIG.'client-key.pem';
$ssl_cert = CONFIG.'client-cert.pem';
$ssl_ca = CONFIG.'server-ca.pem';

$pdo = new PDO('mysql:host=xxx.xxx.xxx.xxx;dbname=db_name_x', 'user_name_x', 'pass_x', array(
    PDO::MYSQL_ATTR_SSL_KEY   => '/path/full/client-key.pem',
    PDO::MYSQL_ATTR_SSL_CERT  => '/path/full/client-cert.pem',
    PDO::MYSQL_ATTR_SSL_CA    => '/path/full/server-ca.pem',
    PDO::MYSQL_ATTR_SSL_VERIFY_SERVER_CERT => false
    )
);
$statement = $pdo->query("SHOW TABLES;");
var_dump($statement);
$row = $statement->fetch(PDO::FETCH_ASSOC);
echo json_encode($row);
exit();

Ответ 5

У меня была такая же проблема с базой данных MySQL, размещенной в кластере композита.

После поиска и тестирования в течение нескольких часов я обнаружил, что лучшим решением является отключение тестирования сертификата, предоставленного сервером, с помощью флага MYSQLI_CLIENT_SSL_DONT_VERIFY_SERVER_CERT.

Я не проверял это с PDO, но с интерфейсом mysqli он работает для меня. Как правило, эта проблема возникает с базой данных, размещенной на сервере кластера.