可以';t使用ssl连接PDO,但使用ssl的mysqli可以工作


Can't connect with PDO using ssl but mysqli with ssl works

我们通过创建证书、更新my.cnf、创建具有权限并需要SSL的用户、重新启动服务来使用SSL设置mysql,并通过远程连接验证它在服务器端和客户端(通过mysql命令行)都能工作。我还验证了PDO在完全相同的设置下可以正常工作,但在mysql中禁用了用户帐户上的"requiressl",因为它只是无声地失败,并使用了非ssl连接。

然而,当使用PHP应用程序进行连接时,使用PDO强制ssl不起作用,而是使用mysqli强制ssl起作用。我认为他们使用了相同的驱动程序,两者应该都能正常工作。我得到的错误消息是"连接到数据库失败[SQLSTATE[2800][1045]拒绝用户访问",但用户存在,并且此连接可与mysqli(强制ssl)一起使用,并且只有当我在mysql中从用户中删除"require-ssl"时,该连接才可用于PDO。

php 5.5.9CentOS 6.5版(最终版)pdo_mysql 5.5.31

如果我能提供任何其他信息,请告诉我。以下是连接示例,

//mysqli
$conn=mysqli_init();
mysqli_ssl_set($conn, $clientkey, $clientcert, $sharedca, NULL, NULL);
if (!mysqli_real_connect($conn, $host, $user, $pass, $db))
{
    die("Failed connecting to ssl mysql via mysqli");
}
$res = mysqli_query($conn, "SHOW STATUS like 'Ssl_cipher'");
print_r(mysqli_fetch_row($res));
mysqli_close($conn);
//pdo
$options = array_merge($options, array(
PDO::MYSQL_ATTR_SSL_KEY           => $sslkey,
PDO::MYSQL_ATTR_SSL_CERT          => $sslcert,
PDO::MYSQL_ATTR_SSL_CA            => $sslca,
));
try
{
    $pdo = new PDO("mysql:dbname={$db};host={$host}", $user, $pass, $options);  
}
catch( PDOException $e )
{
  die("Failed connecting");
}

关于如何使用SSL与PDO正确连接,我应该知道什么吗?还是因为PDO对SSL的支持可能有问题而被迫切换到mysqli?

实际问题是服务器证书CN验证(不匹配),但报告的错误是PDOException: SQLSTATE[HY000] [2002]

PHP中记录了许多错误,如:71845 71003和Github PR

解决方案是在这些PHP版本之后可以使用这个未记录的属性5.6.22(不确定)、7.0.18(已验证)和7.1.15(不确定

PDO::MYSQL_ATTR_SSL_VERIFY_SERVER_CERT

可能值:truefalse默认值:true

所以你的代码应该看起来像

$pdo = new PDO('mysql:host=XXXXXX;dbname=XXXXXX', 'XXXXXX', 'XXXXXX', array(
    PDO::MYSQL_ATTR_SSL_KEY    =>'/path/to/client-key.pem',
    PDO::MYSQL_ATTR_SSL_CERT   =>'/path/to/client-cert.pem',
    PDO::MYSQL_ATTR_SSL_CA     =>'/path/to/server-ca.pem',
    PDO::MYSQL_ATTR_SSL_VERIFY_SERVER_CERT => false
)

);

以下代码将解决问题

new PDO('mysql:host='.HOST.';dbname='.DBNAME.';charset=utf8', USER, PASSWORD,
    array(
            PDO::MYSQL_ATTR_SSL_KEY    =>'/mysqlsslcertificate1/client-key.pem',
            PDO::MYSQL_ATTR_SSL_CERT=>'/mysqlsslcertificate1/client-cert.pem',
            PDO::MYSQL_ATTR_SSL_CA    =>'/mysqlsslcertificate1/ca-cert.pem'
    )
);