Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Set and verify SSL/TLS version used in Python MySQL connection

  • How can I tell the Python MySQL connector which SSL/TLS protocol to use? Either specific (e.g. TLS1.2) or minimum.

  • How can I check which protocol is used on an established connection?

I've got an app that uses mysql-connector-python (8.0.18). I connect something like this:

cnx = mysql.connector.connect(user='x', password='y', host='localhost', database='xyz')

Usually this gives me no trouble, but recently on a web hosting providers server it stopped working. The error I'm now getting is along the lines of:

mysql.connector.errors.InterfaceError: 2026 (HY000): SSL connection error: error:1408F10B:SSL routines:ssl3_get_record:wrong version number

And (connecting through Flask-SQLAlchemy setup):

_mysql_connector.MySQLInterfaceError: SSL connection error: error:140770FC:SSL routines:SSL23_GET_SERVER_HELLO:unknown protocol

What I can confirm is that if I instead do ssl_disabled=True, as below, it connects properly (but without SSL/TLS I assume):

cnx = mysql.connector.connect(user='x', password='y', host='localhost', database='xyz', ssl_disabled=True)

I cannot alter the providers server, but they say that if I specify a specific version to use, for example TLS1.2, then it should connect properly. They also mention using the ssl.OP_NO_SSLv3 flag, however that is part of the SSLContext setup which I'm unsure how to apply to my connection.

I see that on their MySQL instance (which I cannot edit) they have no value set for:

  • SHOW VARIABLES LIKE 'tls_version'
  • SHOW STATUS LIKE 'Ssl_cipher'
  • SHOW STATUS LIKE 'Ssl_version'
like image 252
Halvor Holsten Strand Avatar asked Dec 12 '19 08:12

Halvor Holsten Strand


4 Answers

According to the MySQL documentation here, there is now a "tls-versions" option in 8.0.18 that allows your to specify the TLS version.

The connections should look something like this.

cnx = mysql.connector.connect(user='x', password='y', host='localhost', database='xyz', tls-versions='tls1.2')

I have not verfied the actual value of tls-versions so you may need to try a couple different values.

like image 153
Ryan Bell Avatar answered Oct 09 '22 16:10

Ryan Bell


In the source code I see a reference to ssl_options.get('version', None): https://github.com/mysql/mysql-connector-python/blob/b034f25ec8037f5d60015bf2ed4ee278ec12fd17/lib/mysql/connector/connection.py#L197

This variable is referenced in switch_to_ssl and is passed to ssl.wrap_socket. The value here can be any of the PROTOCOL_* constants defined in the ssl module - https://docs.python.org/3/library/ssl.html#ssl.PROTOCOL_TLS

The _do_auth method is called from _open_connection, which again is called from the connect method, and the value of ssl_options is self._ssl: https://github.com/mysql/mysql-connector-python/blob/b034f25ec8037f5d60015bf2ed4ee278ec12fd17/lib/mysql/connector/connection.py#L286-L288

There doesn't seem to be a way to control connection._ssl from the connect function, so we'll have to construct the object ourselves:

import ssl
try:
    from mysql.connector.connection_cext import CMySQLConnection as MySQLConnection
except ImportError:
    from mysql.connector.connection import MySQLConnection

connection = MySQLConnection()
connection._ssl['version'] = ssl.PROTOCOL_TLSv1_2
connection.connect(host='localhost', user='root', password='', database='example')

The above code was tested against a mysql Docker container started like this:

docker run --rm -it -e MYSQL_ALLOW_EMPTY_PASSWORD=true -e MYSQL_DATABASE=example -p 127.0.0.1:3306:3306 mysql
like image 41
Andreas Avatar answered Oct 09 '22 17:10

Andreas


Based on my experiments, the order of the import is the issue. The following works:

import mysql.connector
import ssl

The following doesn't work:

import ssl
import mysql.connector

no matter if you set the ssl_ca='', ssl_version=ssl.PROTOCOL_TLSv1_2 or not.

Also you get the same if you import requests instead of import ssl.

like image 28
daN4cat Avatar answered Oct 09 '22 17:10

daN4cat


I took a look at our current configuration:

test env:

mysql> SHOW VARIABLES LIKE "%version%";
+-------------------------+------------------------------+
| Variable_name           | Value                        |
+-------------------------+------------------------------+
| innodb_version          | 5.7.27                       |
| protocol_version        | 10                           |
| slave_type_conversions  |                              |
| tls_version             | TLSv1,TLSv1.1                |
| version                 | 5.7.27                       |
| version_comment         | MySQL Community Server (GPL) |
| version_compile_machine | x86_64                       |
| version_compile_os      | Linux                        |
+-------------------------+------------------------------+
8 rows in set (0.04 sec)

prodcut env:

mysql> SHOW VARIABLES LIKE "%version%";

+----------------------------------+-----------------------+
| Variable_name                    | Value                 |
+----------------------------------+-----------------------+
| innodb_polar_restore_old_version | OFF                   |
| innodb_version                   | 8.0.13                |
| protocol_version                 | 10                    |
| rds_audit_log_version            | MYSQL_V1              |
| rds_version                      | 13                    |
| slave_type_conversions           |                       |
| tls_version                      | TLSv1,TLSv1.1,TLSv1.2 |
| version                          | 8.0.13                |
| version_comment                  | Source distribution   |
| version_compile_machine          | x86_64                |
| version_compile_os               | Linux                 |
| version_compile_zlib             | 1.2.11                |
+----------------------------------+-----------------------+
12 rows in set (0.98 sec)

The previous version used is 8.0.16 and the release is correct. After the automatic update to 8.0.19, the test environment begins to appear the above error,But the production environment is not wrong。

So I added ssl_disabled = True according to the above operation

ssl_disabled=True

But I don’t know how it will affect those things.

I think this is because the 8.0.19 version uses TLSv1.2 by default, so it caused an error in my test environment.But I didn't find relevant documentation

like image 1
hu wentao Avatar answered Oct 09 '22 17:10

hu wentao