MySQL è il database più utilizzato al mondo. Per metterlo al sicuro da eventuali attacchi MiTM sarebbe consigliato configurarlo con il supporto SSL. Purtroppo però sembra che non si comporti sempre nel modo corretto.

Configurare PHP ed effettuare una connessione verso un database MySQL utilizzando SSL è abbastanza semplice. Puoi caricare il tuo certificato e il certificato CA quando effettui la connessione.

$pdo = new PDO('mysql:host=10.199.10.10', 'admin', 'password', array(
PDO::MYSQL_ATTR_SSL_KEY => 'key.pem',
PDO::MYSQL_ATTR_SSL_CERT => 'crt.pem',
PDO::MYSQL_ATTR_SSL_CA => 'ca.pem'
)
);
$statement = $pdo->query("SHOW variables like '%cipher%'");
$row = $statement->fetch(PDO::FETCH_ASSOC);

Prima di eseguire il codice, apri Wireshark e sniffa la connessione. Come vedi sembra tutto normale, vedrai l’handshake SSL e nulla più. Se invece per un momento proviamo a disattivare il supporto SSL sul server MySQL avremo una piccola sorpresa.

In teoria ci si dovrebbe aspettare un errore di connessione, ma in realtà il client si connette senza errori, senza avvisarci che ci troviamo su una connessione non sicura.

Questa vulnerabilità affligge la libreria MySQL Client < 5.7.3 dal manuale di MySQL Client, troviamo questo:

–ssl    For the server, this option is enabled by default as of MySQL 5.7.5, disabled before 5.7.5. With the option enabled, the server enables SSL functionality if possible, so that the server permits but does not require SSL connections. It does not cause the server to refuse to start in the absence of valid SSL certificate and key files.

For clients, the option meaning is version specific:

  • As of MySQL 5.7.3, --ssl requires the client to connect to the server using SSL. If an encrypted connection cannot be established, the connection attempt fails. If the connection attempt succeeds, the connection is guaranteed to use SSL.
  • Before MySQL 5.7.3, --ssl permits but does not require the client to connect to the server using SSL. Therefore, this option is not sufficient in itself to cause an SSL connection to be used. For example, if you specify this option for a client program but the server has not been configured to permit SSL connections, the client falls back to an unencrypted connection.--ssl is implied by other --ssl-xxx options, as indicated in the descriptions for those options.

As of MySQL 5.7.7, client programs attempt to establish an SSL connection by default whenever the server is configured to enable SSL. If an SSL connection cannot be established, the client program falls back to an unencrypted connection. To suppress the attempt at using an unencrypted connection, specify the --ssl=0option.

Questo comporta anche che da PHP non è possibile verificare se la connessione stabilita sia su protocollo sicuro. L’unico modo sarebbe quello di interrogare il server per farsi dire in che modo si è connessi, ma a quel punto credo sia già troppo tardi.

mysql> show variables like "%cipher%"\G
*************************** 1. row ***************************
Variable_name: ssl_cipher
        Value: ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES128-SHA:DES-CBC3-SHA:AES256-SHA:DHE-RSA-AES128-SHA:EDH-RSA-DES-CBC3-SHA:DHE-RSA-AES256-SHA
1 row in set (0.07 sec)

Una delle possibili soluzioni, oltre all’aggiornamento del client, è quella di fare un ALTER USER con cui ci si connette e forzarlo ad una connessione SSL, con REQUIRE SSL.

Spero di esservi stato utile. Se avete domande o suggerimenti scrivetemi nei commenti.

Cheers!