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

Posted

技术标签:

【中文标题】PHP 在连接到 MySql 时忽略 ssl 证书【英文标题】:PHP ignores ssl certificates when connecting to MySql 【发布时间】:2012-12-12 18:05:24 【问题描述】:

使用 php 手册中找到的代码 here 和 here

<?php

$mysqli = mysqli_init();
if (!$mysqli) 
    die('mysqli_init failed');


$mysqli->ssl_set('/path/to/client-key.pem',   
                 '/path/to/client-cert.pem',
                 '/path/to/ca-cert.pem',
                  NULL,NULL); //<-- Doesn't matter if the paths are right or wrong

if (!$mysqli->options(MYSQLI_INIT_COMMAND, 'SET AUTOCOMMIT = 0')) 
    die('Setting MYSQLI_INIT_COMMAND failed');


if (!$mysqli->options(MYSQLI_OPT_CONNECT_TIMEOUT, 5)) 
    die('Setting MYSQLI_OPT_CONNECT_TIMEOUT failed');


if (!$mysqli->real_connect('xx.xx.xx.xx', 'my_user', 'my_password', 'my_db')) 
    die('Connect Error (' . mysqli_connect_errno() . ') '
            . mysqli_connect_error());


echo 'Success... ' . $mysqli->host_info . "\n";

$mysqli->close();
?>

我无法连接到 MySql。它给出了以下错误:

Message: SQLSTATE[28000] [1045] Access denied for user 'my_user'@'xx.xx.xx.xx' (using password: YES) <-- the client IP

我已将问题范围缩小到$mysqli-&gt;ssl_set(...) 这一行。

当我将错误的路径传递给证书时,它应该根据this post 抛出一个SSL certificate error,在用户遇到同样问题的地方,它会抛出相同的先前访问被拒绝错误。

我在数据库管理员的帮助下,通过如下配置 ssl 连接,设法使用 Navicat 与服务器建立了连接:

注意事项:

    我的 PHP 版本是 5.3.15 远程数据库服务器上使用的MySql版本是5.5.13-55 Navicat 和 PHP 代码都在同一台 PC 上运行。 数据库管理员创建了一个 ssl_user 专门用于测试。此用户被拒绝正常访问,必须使用 ssl 连接。 没有使用代理。 我试过PDO 也遇到了同样的问题。 我尝试了mysql-&gt;connect(),但它引发了一个糟糕的握手错误,并且根据manual 中的一些cmets 它不起作用。 从phpinfo()启用开放式ssl

所以问题是为什么 PHP 不抱怨证书的错误路径?似乎 PHP 忽略了我设置证书路径的行!


更新: 我尝试更改建立连接的行以显式设置端口并使用MYSQLI_CLIENT_SSL

$mysqli->real_connect('xx.xx.xx.xx', 'my_user', 'my_password', 'my_db','3306',NULL,MYSQLI_CLIENT_SSL)

但是,我收到了这个错误:

Warning: mysqli::real_connect(): (08S01/1043): Bad handshake in ...

更新 2:

这是从数据库服务器 tcpdump-ing 的结果:

0x0040:  3142 6164 2068 616e 6473 6861 6b65       1Bad.handshake
13:16:18.133282 IP (tos 0x8, ttl  64, id 40823, offset 0, flags [DF], proto: TCP (6), length: 52) xx.xx.xx.202.mysql > xx.xx.xx.130.42766: F, cksum 0xf15f (correct), 112:112(0) ack 79 win 46 <nop,nop,timestamp 19516376 3465907>
        0x0000:  4508 0034 9f77 4000 4006 c8a7 c0a8 28ca  E..4.w@.@.....(.
        0x0010:  c0a8 2882 0cea a70e b36c 7e8b 7b4d a169  ..(......l~.M.i
        0x0020:  8011 002e f15f 0000 0101 080a 0129 cbd8  ....._.......)..
        0x0030:  0034 e2b3                                .4..
13:16:18.133433 IP (tos 0x8, ttl  64, id 17337, offset 0, flags [DF], proto: TCP (6), length: 52) xx.xx.xx.130.42766 > xx.xx.xx.202.mysql: F, cksum 0xb695 (correct), 79:79(0) ack 113 win 92 <nop,nop,timestamp 3480910 19516376>
        0x0000:  4508 0034 43b9 4000 4006 2466 c0a8 2882  E..4C.@.@.$f..(.
        0x0010:  c0a8 28ca a70e 0cea 7b4d a169 b36c 7e8c  ..(.....M.i.l~.
        0x0020:  8011 005c b695 0000 0101 080a 0035 1d4e  ...\.........5.N
        0x0030:  0129 cbd8                                .)..
13:16:18.133452 IP (tos 0x8, ttl  64, id 40824, offset 0, flags [DF], proto: TCP (6), length: 52) xx.xx.xx.202.mysql > xx.xx.xx.130.42766: ., cksum 0xb6c3 (correct), 113:113(0) ack 80 win 46 <nop,nop,timestamp 19516376 3480910>
        0x0000:  4508 0034 9f78 4000 4006 c8a6 c0a8 28ca  E..4.x@.@.....(.
        0x0010:  c0a8 2882 0cea a70e b36c 7e8c 7b4d a16a  ..(......l~.M.j
        0x0020:  8010 002e b6c3 0000 0101 080a 0129 cbd8  .............)..
        0x0030:  0035 1d4e                                .5.N

xx.xx.xx.202是数据库服务器ip。 xx.xx.xx.130 是我的电脑ip。

更新 3:

我使用以下代码检查了密码长度:

mysql> select length(Password) from mysql.user where User='youruser'

密码长度为41

更新 4:

我在远程服务器上通过ssh使用命令行连接时返回的错误消息中可能有提示(我将整个项目上传到远程服务器):

mysql -u test_ssl -password --ssl-key=/usr/local/apache2/htdocs/certs/client-key.pem --ssl-cert=/usr/local/apache2/htdocs/certs/WRONG-CERTIFICATE.pem

我收到以下错误:

SSL error: Unable to get certificate from '/usr/local/apache2/htdocs/certs/WRONG-CERTIFICATE.pem'
ERROR 2026 (HY000): SSL connection error ---> notice the error here

如果我根本不提供任何证书,我会收到以下消息:

-bash-3.2$ mysql -u test_ssl -password
ERROR 1045 (28000): Access denied for user 'test_ssl'@'localhost' (using password: YES)

当我使用 PHP 使用证书的正确或无效路径进行连接时,我遇到了同样的错误!!

也许这意味着什么?

【问题讨论】:

【参考方案1】:

乍一看,您没有将MYSQLI_CLIENT_SSL 选项设置为连接。

if (!$mysqli-&gt;real_connect('localhost', 'my_user', 'my_password', 'my_db', null, MYSQLI_CLIENT_SSL)) ...

更新: 您可以尝试添加$mysqli-&gt;options(MYSQLI_OPT_SSL_VERIFY_SERVER_CERT, true);$mysqli-&gt;ssl_set()之前。

另外,这对我有用:

<?php
$pdo = new PDO('mysql:host=ip;dbname=dbname', 'username', 'password', array(
    PDO::MYSQL_ATTR_SSL_KEY    =>'/etc/mysql/ssl/client-key.pem',
    PDO::MYSQL_ATTR_SSL_CERT=>'/etc/mysql/ssl/client-cert.pem',
    PDO::MYSQL_ATTR_SSL_CA    =>'/etc/mysql/ssl/ca-cert.pem'
    )
);
$stmt = $pdo->query("SHOW TABLES;");
$row = $stmt->fetch(PDO::FETCH_ASSOC);
print_r($row);
?>

更新 2: 如果您使用旧式 mysql 密码(16 字节长),您可能会收到 bad handshake。要检查,请运行以下查询:

mysql> select length(Password) from mysql.user where User='youruser'

如果您收到16:

// disable old_passwords:
mysql> SET @@session.old_passwords = 0;

// update password for user used in PHP script:
mysql> SET PASSWORD FOR 'existinguser'@'localhost' = PASSWORD('existingpass');

// check if we have a 41 bytes long password:
mysql> select length(Password) from mysql.user where User='youruser'

然后再次检查来自 PHP 脚本的连接。

【讨论】:

我添加了MYSQLI_OPT_SSL_VERIFY_SERVER_CERT 行,但同样抛出了(08S01/1043): Bad handshake in ... 错误。当我从real_connect() 中删除MYSQLI_CLIENT_SSL 时,它会给出旧错误Access denied。最后我已经尝试了几天PDO 版本,但它给出了相同的Access denied error @Songo :请您仔细检查服务器的 SSL 配置。您可以使用this post 作为参考。 好的,我会检查一下。虽然我可以使用 Navicat 进行连接,但这真的很奇怪...... @Songo 还在与错误作斗争:)?当我无法使用 ssh 连接到服务器时,我解决了这个问题,转储了 ssh 会话并很快看到,出了什么问题。尝试找到一种方法来转储会话并找出它在哪里中断。目前,我们是盲人。 @user4035 是的,我要死了:D 我正在尝试使用你提到的 tcpdump,但我首先需要系统管理员的权限,目前他已经被占用了:S【参考方案2】:

好吧,我们能够解决问题,但我不确定这是一个实用的解决方案。

首先,我们能够找到问题的根源,即 MySql 客户端库,即 PHP 使用 SSL 连接的那些。 PHP 必须符合这些库才能使用 SSL 进行连接。

此外,MySql 客户端库和 OpenSSL 库之间存在冲突。

解决我们问题的唯一方法是从头开始重新安装所有内容。我们使用了一个新的服务器,全新的 Mysql(最新版​​本)安装了所有库,最新的 PHP 版本和最新的 CentOS 发行版。

【讨论】:

您能否详细介绍一下哪些库以及您如何使用这些库编译 PHP?我遇到了同样的问题和同样的情况。我可以使用终端和 MySQL Workbench 进行连接,但不能使用 PHP,我需要不断告诉 DB 管理员向我发送日志和转储,这些日志和转储直到现在都无法帮助我。

以上是关于PHP 在连接到 MySql 时忽略 ssl 证书的主要内容,如果未能解决你的问题,请参考以下文章

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

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

忽略 Xamarin.Forms (PCL) 中的 SSL 证书错误

从 Java bean 到 Web 服务的 SSL 连接问题

ssl时如何忽略证书检查

php curl 忽略ssl 不是否等于ssl没有用