关于mysqli:PHP基于SSL的MySQL。对等证书不匹配

PHP MySQL over SSL. Peer certificate did not match

我正在尝试通过GCE(Google Compute Engine)实例通过SSL使用Google Cloud SQL。我的问题是我无法通过SSL连接到Cloud SQL实例。

mysql命令正常工作。我可以使用证书文件连接到Cloud SQL实例。

1
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程序访问时,出现如下警告和致命错误。

1
2
3
4
5
6
7
8
9
10
11
<?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);
?>?€€

?€€

1
2
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时出现相同的错误。

1
2
3
4
5
6
7
8
9
$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);

?€€

1
2
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自签名证书,可通过PHP

与Mysql连接

有人知道解决方案吗?

更新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

1
sudo apt-get install php5

2我这样放置MYSQLI_CLIENT_SSL_DONT_VERIFY_SERVER_CERT选项。

1
$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


对于不使用Google云或无法从代理解决方案中受益的PDO连接,他们已修复了该错误,现已合并。
现在有一个常量(从2017年4月开始):

1
PDO::MYSQL_ATTR_SSL_VERIFY_SERVER_CERT => false,

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


简而言之,如果您需要同时从PDO和mysqli进行访问,请使用Cloud SQL代理。您别无选择。

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


对于mysqli,添加:

1
MYSQLI_CLIENT_SSL_DONT_VERIFY_SERVER_CERT

to real_connect()解决了此问题的实例。

示例(根据需要替换主机,用户,密码和数据库):

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

完整的php mysqli SSL连接脚本:

1
2
3
4
5
6
7
8
9
10
11
12
13
// 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);

在组成群集上托管的MySQL数据库时,我遇到了同样的问题。

经过几个小时的搜索和测试,我发现最好的解决方案是使用MYSQLI_CLIENT_SSL_DONT_VERIFY_SERVER_CERT标志禁用对服务器提供的证书的测试。

我还没有使用PDO进行过测试,但是使用mysqli接口,它对我有用。
通常,在群集服务器上托管的数据库中会出现此问题。


CakePHP 3.5.x中的示例PHP 7.1.x SQL Google Cloud SSL

在以下位置更改文件:config / app.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
    ...
    ...

    /**
     * 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纯PDO SSL:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
$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();