Использование кода из руководства по PHP, найденного здесь и здесь
<?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->ssl_set(...)
.
Когда я передаю неправильные пути к сертификатам, он должен SSL certificate error
соответствии с этим сообщением, в котором пользователь пострадал от одной и той же проблемы, вместо этого он выдает ту же самую предыдущую ошибку Access denied.
Мне удалось установить соединение с помощью Navicat на сервере с помощью администратора базы данных, настроив соединение ssl следующим образом:
Заметки:
PDO
и у него такая же проблема. mysql->connect()
, но он выдает плохую рукопожатие, и, согласно некоторым комментариям в руководстве, она не работает. phpinfo()
Поэтому возникает вопрос, почему PHP не жалуется на неправильные пути к сертификатам? Кажется, PHP игнорирует строку, где я устанавливаю пути сертификата!
UPDATE: я попытался изменить строку, в которой я делаю подключение, чтобы явно установить порт и использовать 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~.{Mi 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 ..(.....{Mil~. 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~.{Mj 0x0020: 8010 002e b6c3 0000 0101 080a 0129 cbd8 .............).. 0x0030: 0035 1d4e .5.N
xx.xx.xx.202 – это сервер баз данных.
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, используя правильные или недействительные пути к сертификатам!
Может быть, это что-то значит?
На первый взгляд вы не установили параметр MYSQLI_CLIENT_SSL
для подключения.
if (!$mysqli->real_connect('localhost', 'my_user', 'my_password', 'my_db', null, MYSQLI_CLIENT_SSL)) { ... }
Обновить:
Вы можете попробовать добавить $mysqli->options(MYSQLI_OPT_SSL_VERIFY_SERVER_CERT, true);
перед $mysqli->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); ?>
и<?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: вы можете получить bad handshake
если используете старый mysql-пароль ( длиной 16 байт ). Чтобы проверить, выполните следующий запрос:
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-скриптом.
Ну, мы смогли решить проблему, но я не уверен, что это практическое решение.
Прежде всего, нам удалось найти источник проблемы, который был клиентскими библиотеками MySql, которые PHP использует для подключения с использованием SSL. PHP должен был соответствовать этим библиотекам, чтобы иметь возможность подключаться с использованием SSL.
Кроме того, возник конфликт между клиентскими библиотеками MySql и библиотеками OpenSSL.
Единственным решением нашей проблемы было переустановить все с нуля. Мы использовали новый сервер, новую версию Mysql (последняя сборка) со всеми библиотеками, последней версией PHP и последним дистрибутивом CentOS.