I had considerable difficulty getting mysqli_connect to use SSL/TSL to
connect to a db and I think some things need to be improved. I apologize
for also describing documentation issues here, but I'll describe the coding
issues first. I may need some help to prompt the documentation team to
remedy some issues. It is my feeling that PHP's credibility as a viable
modern language depends in large part on reliable and well-documented
encryption functionality to satisfy security best practices for vital
database connectivity. PHP's documentation has been one of its great assets
over the years and I hope to see that great tradition continued robustly.
CONTEXT
An email from Amazon informed me they are upgrading the certificates for
their Relational Database Servers (RDS). This prompted me to try and
connect from PHP to an RDS MySQL server using SSL/TSL. The experience was
difficult and unhappy. It's tricky mostly because the documentation on
mysqli features relating to SSL/TLS is poor, but also because the
underlying PHP code doesn't make use of a variable (or more?) in the
underlying source code.
CODING/DEV ISSUES
-
As pointed out here
https://stackoverflow.com/questions/54299690/does-mysqli-verify-server-certificates-by-default-when-using-ssl?answertab=votes#tab-top,
the constantMYSQLI_OPT_SSL_VERIFY_SERVER_CERT
is defined in PHP
https://github.com/php/php-src/search?q=MYSQLI_OPT_SSL_VERIFY_SERVER_CERT&unscoped_q=MYSQLI_OPT_SSL_VERIFY_SERVER_CERT
but apparently doesn't do anything at all. A decision needs to be made
about whether to remove this constant or to somehow reconcile its relation
to the constant MYSQLI_CLIENT_SSL_DONT_VERIFY_SERVER_CERT. The former
constant is supplied to the function mysqli_options and does absolutely
nothing, the latter is a flag to the function mysqli_real_connect and does
appear to prevent validation of the server's SSL/TLS certificate during
handshaking. There may be other orphaned variables that are not used, I
don't know. -
If one specifies "localhost" as the host when trying to mysqli_connect
using SSL/TLS, then the connection will fail with these warnings:
PHP Warning:mysqli_real_connect()
: this stream does not support
SSL/crypto in /path/to/file.php on line XX
PHP Warning:mysqli_real_connect()
: Cannot connect to MySQL by using SSL
in /path/to/file.php on line XX
PHP Warning:mysqli_real_connect()
: [2002] (trying to connect via (null))
in /path/to/file.php on line XX
PHP Warning:mysqli_real_connect()
: (HY000/2002): in /path/to/file.php on
line XX
That's four warnings and a highly cryptic problem which is not easily
diagnosed because there is no documentation or user comments to clarify the
issue. Using 127.0.0.1 instead of localhost seems to remedy the problem for
some reason surely related to transport, but it would certainly be
preferable if the PHP code was smart enough to recognize the situation
enough to provide a single, more meaningful warning.
DOCUMENTATION (AND POSSIBLY CODING) ISSUES
A) mysqli_ssl_set https://www.php.net/manual/en/mysqli.ssl-set.php has no
usage examples and the parameter descriptions border on useless. For
example:
key
The path name to the key file.
cert
The path name to the certificate file.
ca
The path name to the certificate authority file.
No mention is made of format. No effort is made to describe whether these
are client keys/certs or server keys/certs. Is this a private key or public
key? I admit my knowledge of the relation between certificates and the
certificate authority file is a little fuzzy, but I'm hardly a novice
programmer and feel this documentation leaves a lot to be desired. Most of
the coding examples I find using this function set only the ca, leaving the
majority of the numerous other parameters empty. The documentation does not
describe what happens when these values are NULL
or what happens of the
specified file paths don't exist. It doesn't describe what string values
are permissible -- which is especially disconcerting for the cipher
parameter, which surely admits only certain constants? For some reason this
function always returns a TRUE
value, and does not throw any exceptions
(e.g., if the files don't exist). What doe these parameters do? What does
this function do?
B) documentation for mysqli_real_connect
https://www.php.net/manual/en/mysqli.real-connect.php does not
sufficiently describe how it differs from mysqli_connect. E.g., it doesn't
mention that mysqli_real_connect is helpful in lieu of mysqli_connect if
you must set options like connect timeouts, etc. It does not provide any
examples that use the flags parameter. Why do we have these two distinct
functions? Is there some way to use mysqli_ssl_set with mysqli_connect? Or
must one always use mysqli_real_connect?
In digging further into the MySQLi documentation, I see that there is a lot
of helpful detail on the Quick Start articles, and would suggest that the
level of detail in Quick Start should be the bare minimum, with the details
being moved into the documentation of the functions themselves.
C) The mysqli_options page
https://www.php.net/manual/en/mysqli.options.php lists
MYSQLI_OPT_SSL_VERIFY_SERVER_CERT
but does not describe anything about it.
As mentioned above, this constant does nothing and should probably be
removed. This page also does not have a link to to the MySQLi predefined
constants page for additional detail.
I hope I haven't offended anyone with this message. I love PHP and want to
see it be the best development language there is.