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

Posted

技术标签:

【中文标题】基于 SSL 的 PHP MySQL。对等证书不匹配【英文标题】:PHP MySQL over SSL. Peer certificate did not match 【发布时间】:2016-07-29 07:57:04 【问题描述】:

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

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 self-signed certifications to connect with Mysql with PHP

有人知道解决方案吗?


更新 1

该错误已报告。 https://bugs.php.net/bug.php?id=71003

这里有非常相似的问题。 Google Cloud SQL SSL fails peer certificate validation

我的 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

有些人指责谷歌对 CN 名称的设计(我实际上同意他们的观点..)

最糟糕的是你们使用不可能的 CN 名称 (:) 。如果 CN 没有冒号,也许我可以在我的 hosts 文件中映射 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();

参考文献(日语)

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

【问题讨论】:

你太棒了。更新#5 完全为我工作。谢谢!!! 我头疼了好几个小时。也许这会帮助别人。第 5 步第 1 部分是我的问题 - 我以 root 身份登录。以普通用户身份重新运行,一切正常! 【参考方案1】:

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

PDO::MYSQL_ATTR_SSL_VERIFY_SERVER_CERT => false,

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

【讨论】:

这是否意味着连接是安全的? 嗯,是的,这是一个加密连接,但请注意您没有验证证书本身。 我知道,但如果不使用上面的代码,我找不到任何解决方案。使用终端或类似续集的应用程序时,证书可以正常工作。但是在php方面我找不到任何解决方案 这仅在您使用 PHP 7.1.x 时有效。如果使用 azure,为 ubuntu 部署的一个好方法是确保使用 Ubuntu 18LTS。这为具有 PDO::MYSQL_ATTR_SSL_VERIFY_SERVER_CERT 的正确 PHP 版本提供了默认值 @javi: 你知道在 PHP 5.6 中有什么方法吗?【参考方案2】:

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

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

【讨论】:

GCP 员工注意事项:PR 不是编辑答案的正当理由。【参考方案3】:

对于mysqli,添加:

MYSQLI_CLIENT_SSL_DONT_VERIFY_SERVER_CERT

real_connect() 解决了我的这个问题。

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

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

完整的 php mysqli SSL 连接脚本:

// 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】:

我在 compose 集群上托管的 MySQL 数据库也遇到了同样的问题。

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

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

【讨论】:

以上是关于基于 SSL 的 PHP MySQL。对等证书不匹配的主要内容,如果未能解决你的问题,请参考以下文章

Android ssl:javax.net.ssl.SSLPeerUnverifiedException:没有对等证书(又一次)

SSL 对等证书或 SSH 远程密钥不正确

Android SSL HttpGet(无对等证书)错误或(对等连接已关闭)错误

如何创建允许 PHP 通过 SSL 连接到 MySQL 的证书?

PHP 在连接到 MySql 时忽略 ssl 证书

使用带有 --ssl 的 PHP PDO 连接到 MySQL/MariaDB,无需证书