PHP MySQL over SSL. Peer certificate did not match
Asked Answered
M

5

22

I'm trying to use Google Cloud SQL over SSL from GCE(Google Compute Engine) instance. My problem is that I cannot connect to Cloud SQL instance over SSL.

mysql command works normally. I can connect to Cloud SQL instance with certification files.

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

However, I got warning and fatal error as followings when I access from PHP program.

<?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

I got same error when I used 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

This question looks be relevant to my case but there is no answer yet. SSL self-signed certifications to connect with Mysql with PHP

Does anyone know about solutions?


Update 1

The bug is reported. https://bugs.php.net/bug.php?id=71003

Very similar question here. Google Cloud SQL SSL fails peer certificate validation

My PHP version is 5.6.14. I will update to 5.6.16 to use MYSQLI_CLIENT_SSL_DONT_VERIFY_SERVER_CERT.


Update 2

Fixed it when I use mysqli

What I did are as followings:

1 I updated my PHP to 5.6.20

sudo apt-get install php5

2 I put the MYSQLI_CLIENT_SSL_DONT_VERIFY_SERVER_CERT option like this.

$mysqli->real_connect('[IP Address]', 'root', 'test', 'testdb', 3306, NULL, MYSQLI_CLIENT_SSL_DONT_VERIFY_SERVER_CERT);

My application uses both mysqli and PDO for some reasons. I'm now looking for PDO's solution.


Update 3

This bug report shows about PDO's case. Sounds not fixed yet.

https://bugs.php.net/bug.php?id=71845

This is also related. https://groups.google.com/forum/?utm_medium=email&utm_source=footer#!msg/google-cloud-sql-discuss/4HNvmq7MpU4/kuSjhkS2AwAJ

As far as I understand, there is no way to resolve for PDO.


Update 4

Some people blame google's design of CN names (I agree with them actually..)

What's worst is you guys use impossible CN names (:) . If the CN was without colon maybe I can map the ip and the CN in my hosts file so that when peer validation is done it can pass. With the colon, php thinks is host and is port

and Google's staff? understand the problem.

I understand the current situation when connecting by IP is not ideal.

But it seems they provide a solution called 'proxy'.

https://groups.google.com/forum/#!topic/google-cloud-sql-discuss/gAzsuCzPlaU

I'm using Cloud SQL second generation and my applications are hosted GCE. So I think I can use the proxy way. I will try it now.


Update 5

Setup the proxy access. Solved both PDO and mysqli access.

Install the proxy on 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();

refs (Japanese)

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

Mayfair answered 8/4, 2016 at 6:34 Comment(2)
you are amazing. update #5 totally worked for me. thank you!!!Lacy
I was banging my head for hours. Maybe this will help someone else. Step 5 part 1 was my issue - I was logged in as root. Re-ran as normal user, all worked as expected!Paymaster
S
15

For PDO connections that don't use Google cloud or cannot benefit from the proxy solution, they have fixed the bug and it is merged now. There is now a constant for this (starting April 2017):

PDO::MYSQL_ATTR_SSL_VERIFY_SERVER_CERT => false,

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

Savagery answered 19/5, 2017 at 10:14 Comment(7)
Does this mean the connection is secured?Wysocki
Well, yes, it is an encrypted connection, but take into account that you are not verifying the cert itself.Savagery
I know but i could not find any solution without using the code of line above. The certificates works fine when using the terminal or an app like sequel. But in terms of php I couldn’t find any solutionWysocki
This only works if you are using PHP 7.1.x. If using azure, a good way to deploy for ubuntu is to ensure using Ubuntu 18LTS. This provides a default for the correct version of PHP that has PDO::MYSQL_ATTR_SSL_VERIFY_SERVER_CERTInput
@javi: do you know of any way this is possible in PHP 5.6?Suppurate
@Max: according to this, it is avalable since 5.6.22: secure.php.net/manual/en/ref.pdo-mysql.php#122326Savagery
I'm using php 5.6.40, but does not support PDO::MYSQL_ATTR_SSL_VERIFY_SERVER_CERT Any other solution for PDO? ThanksCilia
M
4

In short, use Cloud SQL Proxy if you need to access from both PDO and mysqli. You have no choice.

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

Mayfair answered 8/4, 2016 at 17:33 Comment(1)
Note to GCP employees: PR is not a valid reason to edit answers.Witcher
P
4

For mysqli, adding:

MYSQLI_CLIENT_SSL_DONT_VERIFY_SERVER_CERT

to real_connect() solved my instance of this issue.

Example (replace host, user, password and database as needed):

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

Full php mysqli SSL connection script:

// 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);
Pacorro answered 23/4, 2018 at 23:35 Comment(0)
B
1

Example in CakePHP 3.5.x + PHP 7.1.x + SQL Google Cloud + SSL

Change file in: 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'],
    ],
 ],
 ...
 ...

Example 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();
Bucella answered 25/1, 2018 at 4:0 Comment(0)
D
0

I had the same problem with a MySQL database hosted at compose cluster.

After searching and testing for hours, I found out that the best solution is to disable testing the certificate provided by the server by using the MYSQLI_CLIENT_SSL_DONT_VERIFY_SERVER_CERT flag.

I haven't tested it with PDO but with the mysqli interface it is working for me. In general this problem would appear with a database hosted at a cluster server.

Deuterium answered 3/7, 2019 at 14:55 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.