设置和验证 Python MySQL 连接中使用的 SSL/TLS 版本

Hal*_*and 5 python mysql ssl mysql-connector-python

  • 如何告诉 Python MySQL 连接器使用哪个 SSL/TLS 协议?特定的(例如 TLS1.2)或最低的。

  • 如何检查已建立的连接使用了哪种协议?

我有一个使用mysql-connector-python(8.0.18)的应用程序。我连接这样的东西:

cnx = mysql.connector.connect(user='x', password='y', host='localhost', database='xyz')
Run Code Online (Sandbox Code Playgroud)

通常这不会给我带来麻烦,但最近在网络托管提供商服务器上它停止工作。我现在得到的错误是:

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

并且(通过 Flask-SQLAlchemy 设置连接):

_mysql_connector.MySQLInterfaceError: SSL connection error: error:140770FC:SSL routines:SSL23_GET_SERVER_HELLO:unknown protocol
Run Code Online (Sandbox Code Playgroud)

我可以确认的是,如果我改为这样做ssl_disabled=True,如下所示,它可以正确连接(但我假设没有 SSL/TLS):

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

我无法更改提供者服务器,但他们说如果我指定要使用的特定版本,例如 TLS1.2,那么它应该可以正确连接。他们还提到使用ssl.OP_NO_SSLv3flag,但是这是 SSLContext 设置的一部分,我不确定如何应用于我的连接。

我看到在他们的 MySQL 实例(我无法编辑)上他们没有设置值:

  • SHOW VARIABLES LIKE 'tls_version'
  • SHOW STATUS LIKE 'Ssl_cipher'
  • SHOW STATUS LIKE 'Ssl_version'

Hal*_*and 0

根据我最近的理解和安德烈亚斯回答的帮助,我最终得到了以下连接:

cnx = mysql.connector.connect(user='u', password='p', host='localhost', database='db', ssl_ca='', ssl_version=ssl.PROTOCOL_TLSv1_2)
Run Code Online (Sandbox Code Playgroud)

查看来源,显然所有kwargs提供的内容都mysql.connector.constants.DEFAULT_CONFIGURATION被接受。这包括文档中未包含的一些内容,例如ssl_versionssl_cipher。这种从 到连接的映射kwargs似乎发生在MySQLConnectionAbstract.connect. 请注意,设置ssl_version可能还需要一些其他 kwargs。我需要ssl_ca连同它一起提供(可能会有所不同,具体取决于您的 MySQL 实例中的内容SHOW VARIABLES LIKE '%ssl%')。

考虑到这一点,我得到了以下 MVCE 代码:

import mysql.connector
import ssl

cnx = mysql.connector.connect(user='u', password='p', host='localhost', database='db', ssl_ca='', ssl_version=ssl.PROTOCOL_TLSv1_2)
cursor = cnx.cursor()
cursor.execute("SELECT 1")

for (number,) in cursor:
    print('Number:', number)
print('SSL active:', cnx._ssl_active)
print('Connection SSL version:', cnx._ssl.get("version"))
print("Socket SSL version:", cnx._socket.sock.ssl_version)

cursor.close()
cnx.close()
Run Code Online (Sandbox Code Playgroud)

对我来说输出:

Number: 1
SSL active: True
Connection SSL version: _SSLMethod.PROTOCOL_TLSv1_2
Socket SSL version: _SSLMethod.PROTOCOL_TLSv1_2
Run Code Online (Sandbox Code Playgroud)

如果我在没有指定的情况下进行相同的连接,ssl_version我会得到:

Number: 1
SSL active: True
Connection SSL version: None
Socket SSL version: _SSLMethod.PROTOCOL_TLS
Run Code Online (Sandbox Code Playgroud)

如果您ssl.PROTOCOL_TLSv1_2ssl.PROTOCOL_SSLv23它替换,至少应该尝试不同的协议,但如果存在问题(例如不受支持),则可能会失败。