Weblog entry #73 for dkg

PHP, MySQL, and SSL?
Posted by dkg on Mon 7 Mar 2011 at 06:02
Is there a way to access a MySQL database over the network from PHP and be confident that
  • the connection is actually using SSL, and
  • the server's X.509 certificate was successfully verified?

As far as i can tell, when using the stock MySQL bindings, setting MYSQL_CLIENT_SSL is purely advisory (i.e. it won't fail if the server doesn't advertise SSL support). This means it won't defend against an active network attacker performing the equivalent of sslstrip.

Even if MYSQL_CLIENT_SSL was stronger than an advisory flag, i can't seem to come up with a way to tell PHP's basic MySQL bindings the equivalent of the --ssl-ca flag to the mysql client binary. Without being able to configure this, a "man-in-the-middle" should be able to intercept the connection by offering their own certificate on their endpoint, and otherwise relaying the traffic. A client that does not verify the server's identity would be none the wiser.

One option to avoid a MITM attack would be for the server to require client-side certs via the REQUIRE option for a GRANT statement, but the basic MySQL bindings for php don't seem to support that either.

PHP's mysqli bindings (MySQL Improved, i think) feature a command called ssl_set() which appears to allow client-side certificate support. But its documentation isn't clear on how it handles an invalid/expired/revoked server certificate (let alone a server that announces that it doesn't support SSL), and it also mentions:

This function does nothing unless OpenSSL support is enabled.
Given that debian MySQL packages don't use OpenSSL because of licensing incompatibilities with the GPL, i'm left wondering if packages built against yaSSL support this feature. And i'm more than a little bit leery that i have no way of telling whether my configuration request succeeded, or whether this function just happily did nothing because the interpreter got re-built with the wrong flags. Shouldn't the function fail explicitly if it cannot meet the user's request?

Meanwhile, the PDO bindings for MySQL apparently don't support SSL connections at all.

What's going on here? Does no one use MySQL over the network via PHP? Given the number of LAMP-driven data centers, this seems pretty unlikely. Do PHP+MySQL users just not care about privacy or integrity of their data?

Or (please let this be the case) have i just somehow missed the obvious documentation?


Comments on this Entry

Posted by Anonymous (173.50.xx.xx) on Mon 7 Mar 2011 at 06:34
"Do PHP+MySQL users just not care about privacy or integrity of their data?"

They use PHP, so no to the first (you need security to guarantee privacy). And they use MySQL, so no to the second.

[ Parent | Reply to this comment ]

Posted by Anonymous (195.93.xx.xx) on Mon 7 Mar 2011 at 07:54
Sorry, but this is pure PHP/MySQL bashing and doesn't help at all.

The other comment is much more helpful: If you trust the server on which you run the PHP part (if you didn't, SSL won't help), then running STunnel on the PHP server might be a suitable workaround. At least that way you could ensure that the connection to the MySQL server is indeed encrypted and that the servers certificate is valid.


[ Parent | Reply to this comment ]

Posted by dkg (216.254.xx.xx) on Mon 7 Mar 2011 at 17:13
[ View dkg's Scratchpad | View Weblogs ]
Sigh. I can see now how my rhetorical question might have been seen as an invitation to trollish behavior. I apologize about that, and i hope more people don't follow suit.

A note about vocabulary: I consider "security" (in the information/communications context) to be an epiphenomenon that arises from a collection of contributing factors, two of which are privacy and integrity. So no, you don't need security to guarantee privacy, it's the other way around. Maybe your argument is that you think PHP is poorly engineered, and you actually mean "you need good engineering to guarantee privacy".

As for your claim that MySQL has data integrity issues, i'm actually kind of surprised to hear this. While MySQL is not my favorite relational database, i don't have the impression that it actually loses or mangled data. Am i naive about this? If you're serious (and not just baiting), i'd appreciate some links to back up this claim.

[ Parent | Reply to this comment ]

Posted by Anonymous (59.148.xx.xx) on Mon 7 Mar 2011 at 07:00
stunnel as a ssl proxy.

[ Parent | Reply to this comment ]

Posted by Anonymous (122.104.xx.xx) on Mon 7 Mar 2011 at 08:14
I would assume most people keep MySQL behind a firewall and on a private network segment (or just using localhost), which is probably private enough for most.

[ Parent | Reply to this comment ]

Posted by Anonymous (178.16.xx.xx) on Mon 7 Mar 2011 at 14:48
Shouldn't you be enforcing this on the MySQL side?

[ Parent | Reply to this comment ]

Posted by dkg (2001:0xx:0xx:0xxx:0xxx:0xxx:xx) on Tue 8 Mar 2011 at 15:16
[ View dkg's Scratchpad | View Weblogs ]
Yes, you should require SSL on the server side. But this doesn't protect you from an attacker in control of the network.

Consider a classic "man-in-the-middle", able to intercept and relay traffic. The attacker could receive a connection from the client intended for the database server. The attacker pretends (to the client) that it is the server, and says "Sorry, i can't offer SSL right now" (or initiates SSL with its own public key and X.509 certificate), while simultaneously connecting to the server (pretending to be the client) using SSL.

If the client is willing to accept a connection that doesn't use SSL (or doesn't bother checking the server's presented key), then it will go ahead and send traffic to the attacker, who can relay it (under SSL) to the server.

So the server side requirement doesn't solve the problem on its own.

[ Parent | Reply to this comment ]

Posted by Anonymous (98.124.xx.xx) on Mon 7 Mar 2011 at 21:13
True, one would normally bind to localhost alone, or use the domain socket alone on the same machine. One would never leave the MySQL port publicly accessible, SSH or not. If it were necessary then a VPN or tunnel would be used, as other commenters have said, rendering the complaint moot.

[ Parent | Reply to this comment ]

Posted by dkg (2001:0xx:0xx:0xxx:0xxx:0xxx:xx) on Tue 8 Mar 2011 at 15:30
[ View dkg's Scratchpad | View Weblogs ]
I'm not sure how the complaint is moot. If MySQL offered only a UNIX-domain socket, then sure -- it would be clear to the database admins and the other users that exposure to the network needs to be set up responsibly in some other way. (SSH tunnels, stunnel, VPN, etc).

As it stands, though, both the MySQL daemon and the PHP client-side bindings offer the ability to use network access. And the MySQL daemon itself actually offers reasonable, standards-based encrypted connections as far as i can tell.

The problem is that PHP appears to have no way to make robust use of these security guarantees when connecting to a MySQL daemon over the network. The complaint is that PHP's MySQL bindings should either:

  • provide the ability to make use of the standard secure network connections offered by the underlying library, or
  • remove the possibility of using a network channel entirely -- or at least make it clear that the half-measures they do provide are insufficient to guarantee privacy and data integrity in the face of a hostile network.

[ Parent | Reply to this comment ]