设置并验证在 Python MySQL 连接中使用的 SSL/TLS 版本
Set and verify SSL/TLS version used in Python MySQL connection
如何告诉 Python MySQL 连接器使用哪个 SSL/TLS 协议?具体(例如 TLS1.2)或最小值。
如何检查已建立的连接使用的协议?
我有一个使用 mysql-connector-python
(8.0.18) 的应用程序。我这样连接:
cnx = mysql.connector.connect(user='x', password='y', host='localhost', database='xyz')
通常这不会给我带来麻烦,但最近在网络托管服务提供商的服务器上它停止工作了。我现在得到的错误是:
mysql.connector.errors.InterfaceError: 2026 (HY000): SSL connection error: error:1408F10B:SSL routines:ssl3_get_record:wrong version number
并且(通过 Flask-SQLAlchemy 设置连接):
_mysql_connector.MySQLInterfaceError: SSL connection error: error:140770FC:SSL routines:SSL23_GET_SERVER_HELLO:unknown protocol
我可以确认的是,如果我改为 ssl_disabled=True
,如下所示,它会正确连接(但我假设没有 SSL/TLS):
cnx = mysql.connector.connect(user='x', password='y', host='localhost', database='xyz', ssl_disabled=True)
我无法更改提供商服务器,但他们说如果我指定要使用的特定版本,例如 TLS1.2,那么它应该可以正确连接。他们还提到使用 ssl.OP_NO_SSLv3
flag,但这是 SSLContext 设置的一部分,我不确定如何将其应用于我的连接。
我看到在他们的 MySQL 实例(我无法编辑)上他们没有设置值:
SHOW VARIABLES LIKE 'tls_version'
SHOW STATUS LIKE 'Ssl_cipher'
SHOW STATUS LIKE 'Ssl_version'
根据 MySQL 文档 here,现在 8.0.18 中有一个 "tls-versions" 选项,允许您指定 TLS 版本。
连接应如下所示。
cnx = mysql.connector.connect(user='x', password='y', host='localhost', database='xyz', tls-versions='tls1.2')
我尚未验证 tls-versions 的实际值,因此您可能需要尝试几个不同的值。
在源代码中我看到对 ssl_options.get('version', None)
的引用:https://github.com/mysql/mysql-connector-python/blob/b034f25ec8037f5d60015bf2ed4ee278ec12fd17/lib/mysql/connector/connection.py#L197
此变量在 switch_to_ssl
中被引用并传递给 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
_do_auth
方法是从_open_connection
调用的,_open_connection
又是从connect
方法调用的,ssl_options
的值为self._ssl
: https://github.com/mysql/mysql-connector-python/blob/b034f25ec8037f5d60015bf2ed4ee278ec12fd17/lib/mysql/connector/connection.py#L286-L288
似乎没有办法从connect
函数控制connection._ssl
,所以我们必须自己构造对象:
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')
以上代码针对 mysql Docker 容器进行了测试,容器启动方式如下:
docker run --rm -it -e MYSQL_ALLOW_EMPTY_PASSWORD=true -e MYSQL_DATABASE=example -p 127.0.0.1:3306:3306 mysql
根据我最近的理解和 的帮助,我得到了以下连接:
cnx = mysql.connector.connect(user='u', password='p', host='localhost', database='db', ssl_ca='', ssl_version=ssl.PROTOCOL_TLSv1_2)
查看源代码,显然所有 kwargs
都在 mysql.connector.constants.DEFAULT_CONFIGURATION
are accepted. This includes several that are not included in the documentation, like ssl_version
and ssl_cipher
. This mapping from kwargs
to the connection appears to happen in 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()
对我来说输出:
Number: 1
SSL active: True
Connection SSL version: _SSLMethod.PROTOCOL_TLSv1_2
Socket SSL version: _SSLMethod.PROTOCOL_TLSv1_2
如果我在不指定 ssl_version
的情况下进行相同的连接,我会得到:
Number: 1
SSL active: True
Connection SSL version: None
Socket SSL version: _SSLMethod.PROTOCOL_TLS
如果您将 ssl.PROTOCOL_TLSv1_2
替换为 ssl.PROTOCOL_SSLv23
,它至少应该尝试不同的协议,但如果存在问题(例如不受支持)可能会失败。
根据我的实验,导入顺序是问题所在。
以下作品:
import mysql.connector
import ssl
以下无效:
import ssl
import mysql.connector
不管你有没有设置ssl_ca='', ssl_version=ssl.PROTOCOL_TLSv1_2
。
如果你 import requests
而不是 import ssl
,你也会得到相同的结果。
我看了一下我们现在的配置:
测试环境:
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)
产品环境:
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)
之前使用的版本是8.0.16,release是正确的。自动更新到8.0.19后测试环境开始出现上面的错误,但是生产环境是没有错的。
所以我根据上面的操作添加了ssl_disabled = True
ssl_disabled=True
但我不知道它会如何影响那些东西。
我想这是因为8.0.19版本默认使用TLSv1.2,所以导致我测试出错environment.But没找到相关文档
如何告诉 Python MySQL 连接器使用哪个 SSL/TLS 协议?具体(例如 TLS1.2)或最小值。
如何检查已建立的连接使用的协议?
我有一个使用 mysql-connector-python
(8.0.18) 的应用程序。我这样连接:
cnx = mysql.connector.connect(user='x', password='y', host='localhost', database='xyz')
通常这不会给我带来麻烦,但最近在网络托管服务提供商的服务器上它停止工作了。我现在得到的错误是:
mysql.connector.errors.InterfaceError: 2026 (HY000): SSL connection error: error:1408F10B:SSL routines:ssl3_get_record:wrong version number
并且(通过 Flask-SQLAlchemy 设置连接):
_mysql_connector.MySQLInterfaceError: SSL connection error: error:140770FC:SSL routines:SSL23_GET_SERVER_HELLO:unknown protocol
我可以确认的是,如果我改为 ssl_disabled=True
,如下所示,它会正确连接(但我假设没有 SSL/TLS):
cnx = mysql.connector.connect(user='x', password='y', host='localhost', database='xyz', ssl_disabled=True)
我无法更改提供商服务器,但他们说如果我指定要使用的特定版本,例如 TLS1.2,那么它应该可以正确连接。他们还提到使用 ssl.OP_NO_SSLv3
flag,但这是 SSLContext 设置的一部分,我不确定如何将其应用于我的连接。
我看到在他们的 MySQL 实例(我无法编辑)上他们没有设置值:
SHOW VARIABLES LIKE 'tls_version'
SHOW STATUS LIKE 'Ssl_cipher'
SHOW STATUS LIKE 'Ssl_version'
根据 MySQL 文档 here,现在 8.0.18 中有一个 "tls-versions" 选项,允许您指定 TLS 版本。
连接应如下所示。
cnx = mysql.connector.connect(user='x', password='y', host='localhost', database='xyz', tls-versions='tls1.2')
我尚未验证 tls-versions 的实际值,因此您可能需要尝试几个不同的值。
在源代码中我看到对 ssl_options.get('version', None)
的引用:https://github.com/mysql/mysql-connector-python/blob/b034f25ec8037f5d60015bf2ed4ee278ec12fd17/lib/mysql/connector/connection.py#L197
此变量在 switch_to_ssl
中被引用并传递给 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
_do_auth
方法是从_open_connection
调用的,_open_connection
又是从connect
方法调用的,ssl_options
的值为self._ssl
: https://github.com/mysql/mysql-connector-python/blob/b034f25ec8037f5d60015bf2ed4ee278ec12fd17/lib/mysql/connector/connection.py#L286-L288
似乎没有办法从connect
函数控制connection._ssl
,所以我们必须自己构造对象:
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')
以上代码针对 mysql Docker 容器进行了测试,容器启动方式如下:
docker run --rm -it -e MYSQL_ALLOW_EMPTY_PASSWORD=true -e MYSQL_DATABASE=example -p 127.0.0.1:3306:3306 mysql
根据我最近的理解和
cnx = mysql.connector.connect(user='u', password='p', host='localhost', database='db', ssl_ca='', ssl_version=ssl.PROTOCOL_TLSv1_2)
查看源代码,显然所有 kwargs
都在 mysql.connector.constants.DEFAULT_CONFIGURATION
are accepted. This includes several that are not included in the documentation, like ssl_version
and ssl_cipher
. This mapping from kwargs
to the connection appears to happen in 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()
对我来说输出:
Number: 1
SSL active: True
Connection SSL version: _SSLMethod.PROTOCOL_TLSv1_2
Socket SSL version: _SSLMethod.PROTOCOL_TLSv1_2
如果我在不指定 ssl_version
的情况下进行相同的连接,我会得到:
Number: 1
SSL active: True
Connection SSL version: None
Socket SSL version: _SSLMethod.PROTOCOL_TLS
如果您将 ssl.PROTOCOL_TLSv1_2
替换为 ssl.PROTOCOL_SSLv23
,它至少应该尝试不同的协议,但如果存在问题(例如不受支持)可能会失败。
根据我的实验,导入顺序是问题所在。 以下作品:
import mysql.connector
import ssl
以下无效:
import ssl
import mysql.connector
不管你有没有设置ssl_ca='', ssl_version=ssl.PROTOCOL_TLSv1_2
。
如果你 import requests
而不是 import ssl
,你也会得到相同的结果。
我看了一下我们现在的配置:
测试环境:
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)
产品环境:
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)
之前使用的版本是8.0.16,release是正确的。自动更新到8.0.19后测试环境开始出现上面的错误,但是生产环境是没有错的。
所以我根据上面的操作添加了ssl_disabled = True
ssl_disabled=True
但我不知道它会如何影响那些东西。
我想这是因为8.0.19版本默认使用TLSv1.2,所以导致我测试出错environment.But没找到相关文档