Welcome Guest, Not a member yet? Register   Sign In
MySQLi and SSL connections
#1

In the MySQLi driver, there's a version check when attempting a connection with SSL:
https://github.com/bcit-ci/CodeIgniter/b...r.php#L207

(also in develop: https://github.com/bcit-ci/CodeIgniter/b...r.php#L207 )

PHP Code:
// Prior to version 5.7.3, MySQL silently downgrades to an unencrypted connection if SSL setup fails
if (
    ($client_flags MYSQLI_CLIENT_SSL)
    && version_compare($this->_mysqli->client_info'5.7.3''<=')
    && empty($this->_mysqli->query("SHOW STATUS LIKE 'ssl_cipher'")->fetch_object()->Value)
)


After a little testing, I believe this check is incorrect (it's not particularly dangerous, as I believe this version_compare() call will return true in most environments, but that does mean the query() will run when it doesn't need to).

I believe that the MySQL version referenced in the comment is the version of the MySQL server. The referenced change is also mentioned in the MySQL documentation: http://dev.mysql.com/doc/refman/5.7/en/s...eneral_ssl

$this->_mysqli->client_info returns the version of the PHP MySQLi client, which does not share version numbers with the MySQL database. I believe the version numbers referenced in the MySQL documentation are specific to the MySQL Server to which you are connecting, and the version number of the PHP MySQLi client does not have any impact on the behavior described. The default version numbers for the mysqlnd client in PHP 5.x are listed here: http://php.net/manual/en/mysqlnd.plugin.obtaining.php

In my PHP 7 installation, the mysqlnd client version is 5.0.12.

I didn't have any luck finding the client version numbers for libmysqlclient. The default clients used for 5.x versions of PHP's MySQLi extension are listed here: http://php.net/manual/en/mysqli.installation.php

It seems likely that the code should be changed to:

PHP Code:
// Prior to version 5.7.3, MySQL silently downgrades to an unencrypted connection if SSL setup fails
if (
    ($client_flags MYSQLI_CLIENT_SSL)
    && version_compare($this->_mysqli->server_info'5.7.3''<=')
    && empty($this->_mysqli->query("SHOW STATUS LIKE 'ssl_cipher'")->fetch_object()->Value)
)

Reply
#2

Nope, it's the client that falls back to an unencrypted connection if the SSL one fails. And that's written on the very page you've linked:

Quote:For MySQL client programs, the --ssl option is used as follows:

...

   - Before MySQL 5.7.3, --ssl is advisory: --ssl permits but does not require the client to connect to the server using encryption. Therefore, this option is not sufficient in itself to cause a secure connection to be used. For example, if you specify this option for a client program but the server has not been configured to support secure connections, the client falls back to an unencrypted connection.
Reply
#3

I'm aware that the client is performing the fallback, but the version numbers referenced in the documentation are the server versions, which don't match up with the PHP client version numbers unless you use a specific distribution of the libmysqlclient.

The client version for the mysqlnd client that shipped with PHP 7 is 5.0.12, so this:

PHP Code:
version_compare($this->_mysqli->client_info'5.7.3''<='

will always return true for mysqlnd.

libmysqlclient appears to be up to version 6.1.8, though the MySQL server version is only 5.7.11. The change in behavior noted in the comment appears to have been implemented in libmysqlclient in version 6.1.3: http://dev.mysql.com/doc/relnotes/connec...6-1-3.html

Other notes in that same release point to mysql_get_client_info() returning the server version for the MySQL distribution of the libmysqlclient while it returns the library version in Connector/C distributions. This means that the valid values are different based on which distribution was used. Since the Connector/C version number will be higher than the MySQL distribution number, and the change was implemented at the same time as this particular version check, it should be fine, as long as the client still exhibits the same behavior when connecting to older servers.

So, the check will succeed if you are using libmysqlclient versions newer than 6.1.3, but the check will fail on mysqlnd regardless of version. The behavior when the check fails is not dangerous in any obvious way, but is causing an unnecessary query. mysqlnd was added in PHP 5.3 and was made the default client for all of PHP's mysql extensions in 5.4, so, over time, it seems likely that mysqlnd will become the more common of the two clients.
Reply
#4

(02-16-2016, 01:53 PM)mwhitney Wrote: I'm aware that the client is performing the fallback, but the version numbers referenced in the documentation are the server versions, which don't match up with the PHP client version numbers unless you use a specific distribution of the libmysqlclient.

I don't understand how you've come to the conclusion that the referenced documentation talks about the server as opposed to the client. I very intentionally bolded the word "client" when quoting the document, exactly so that we avoid such confusion.

And if you're not disputing that it is in fact the client that makes the fallback, then how does that even make sense? Would the client check the server version before proceeding with the fallback? That would be completely illogical and therefore I won't believe that until I see it. Smile

If you need more proof, here it is:

Quote:Incompatible Change: Previously, the --ssl option has been treated as advisory: When given, a secure connection was permitted but not required. Also, several other --ssl-xxx options implied --ssl. Because of this, the option was usually not used explicitly as --ssl, but in its negated form as --ssl=0, which prevents use of encryption. This was true on both the client and server sides, and true for any synonyms of --ssl (--ssl=1, --enable-ssl) or --ssl=0 (--skip-ssl, --disable-ssl).

Now the meaning of --ssl has changed on the client-side only. (There are no secure-connection changes on the server side.)

Source: http://dev.mysql.com/doc/relnotes/mysql/...3-security

(02-16-2016, 01:53 PM)mwhitney Wrote: The client version for the mysqlnd client that shipped with PHP 7 is 5.0.12, so this:

PHP Code:
version_compare($this->_mysqli->client_info'5.7.3''<='

will always return true for mysqlnd.

libmysqlclient appears to be up to version 6.1.8, though the MySQL server version is only 5.7.11. The change in behavior noted in the comment appears to have been implemented in libmysqlclient in version 6.1.3: http://dev.mysql.com/doc/relnotes/connec...6-1-3.html

Other notes in that same release point to mysql_get_client_info() returning the server version for the MySQL distribution of the libmysqlclient while it returns the library version in Connector/C distributions. This means that the valid values are different based on which distribution was used. Since the Connector/C version number will be higher than the MySQL distribution number, and the change was implemented at the same time as this particular version check, it should be fine, as long as the client still exhibits the same behavior when connecting to older servers.

So, the check will succeed if you are using libmysqlclient versions newer than 6.1.3, but the check will fail on mysqlnd regardless of version. The behavior when the check fails is not dangerous in any obvious way, but is causing an unnecessary query. mysqlnd was added in PHP 5.3 and was made the default client for all of PHP's mysql extensions in 5.4, so, over time, it seems likely that mysqlnd will become the more common of the two clients.

I think you are incorrectly equating libmysqlclient to Connector/C, but I could see mysqlnd messing things up (it's always been a special case for PHP) and sure - we could do something about that. But checking the server version isn't that something. Smile
Reply
#5

(02-16-2016, 02:38 PM)Narf Wrote: I don't understand how you've come to the conclusion that the referenced documentation talks about the server as opposed to the client. I very intentionally bolded the word "client" when quoting the document, exactly so that we avoid such confusion.

And if you're not disputing that it is in fact the client that makes the fallback, then how does that even make sense? Would the client check the server version before proceeding with the fallback? That would be completely illogical and therefore I won't believe that until I see it. Smile

I'm not disputing that the documentation and behavior is based on the client. I'm disputing the version number referenced in both the documentation and the code. In fact, I am also now in complete agreement with you on the fact that my initial code "fix" will not work correctly.

(02-16-2016, 02:38 PM)Narf Wrote: I think you are incorrectly equating libmysqlclient to Connector/C, but I could see mysqlnd messing things up (it's always been a special case for PHP) and sure - we could do something about that. But checking the server version isn't that something. Smile

I would be more than happy to use some other reference for version numbers for libmysqlclient. Unfortunately, the documentation for Connector/C is the only thing I have found, so far, that details the behavior of libmysqlclient.

As stated here: https://dev.mysql.com/doc/refman/5.7/en/...tions.html
Connector/C distributions include libmysqlclient. (Note: the MySQL PHP API documentation linked from that page is more or less a copy of the PHP mysqlnd documentation.)

As stated in the previous link, the version number returned by client_info in the MySQL Server distribution of libmysqlclient is the same number as the version of the server with which it was distributed. The version number returned by client_info in the Connector/C distribution is the version of the client, which is a higher number than the version of the server with which the same code was distributed.

For this particular check, the problem will only really occur on mysqlnd, though that will mostly likely become the more commonly-used client over time. If there is ever a need to check the client version for some feature introduced in a server version higher than 5.7.3, checking client_info will be more problematic, as libmysqlclient will require a check against two different version numbers and mysqlnd will require a check against a third version number. The whole problem is made worse by the fact that most of the documentation references either the server version or the PHP version (the latter being the case primarily for mysqlnd), while documentation of the actual client versions is rather sparse.
Reply
#6

I'm still looking into this...

It looks like the use of mysqlnd can be checked with something like this:

PHP Code:
if (strpos($this->mysqli->client_info'mysqlnd ') !== false)
{
    
// using mysqlnd instead of libmysqlclient


Since mysqlnd didn't support SSL before PHP 5.3.3, it's a question of whether this problem ever existed in mysqlnd, and, if so, how to detect it. Apparently, the client version of mysqlnd didn't change when SSL support was added (if we believe the version numbers listed in the PHP manual: http://php.net/manual/en/mysqlnd.plugin.obtaining.php ). This would imply that the PHP version should be checked if mysqlnd is in use, rather than the client version.
Reply




Theme © iAndrew 2016 - Forum software by © MyBB