我正在尝试连接到公司的MySQL数据库。该政策是我要使用SSL连接 。
我获得了username
,CA certificate
,certificate
和private key
。
如果我使用HeidiSQL,我可以毫无问题地连接。
但是,我无法使用 Python 2.7.11 与mysql-connector-python-rf
(v2.1.3)进行连接。
这是我的简单连接测试程序:
from __future__ import print_function, division, unicode_literals
import mysql.connector
from mysql.connector.constants import ClientFlag
cnx = mysql.connector.connect(
user='myusername',
host='myserver.example.com',
port=3306,
client_flags=[ClientFlag.SSL],
ssl_ca='/path/to/ca.crt',
ssl_cert='/path/to/user.crt',
ssl_key='/path/to/user.key'
)
cnx.close()
我总是以这个例外结束:
mysql.connector.errors.InterfaceError: 2055: Lost connection to MySQL server at
'myserver.example.com:3306', system error: 1 [SSL: SSL_NEGATIVE_LENGTH] dh key too small
(_ssl.c:590)
我已尝试搜索答案,但除了更改服务器端上的设置外似乎没有解决方案,这只是一个禁忌。
如何修复和/或解决此问题?
更新更多信息:我正在使用 PyCharm 5.0.3
在Windows 10上创建我的程序答案 0 :(得分:3)
这是一个安全问题,服务器端受weak DH key影响。当前版本的OpenSSL强制使用最小长度的DH密钥以防止使用弱DH密钥的攻击。
如果您的公司真的对安全性感兴趣,而不仅仅是相信神奇地洒下一些(不安全的)SSL就可以了,那么他们应该在服务器端修复问题。要解决客户端问题,您需要将Python链接到旧版本的OpenSSL,而OpenSSL尚未强制实施最小DH密钥长度。
答案 1 :(得分:3)
在撰写本文时,使用Oracle的mysql-connector-python 2.1.4纯python模块(您正在使用的是2.1.3版本的分支)支持您的未记录的连接配置kwarg ssl_cipher
连接字符串(因为它基本上将它传递给python' s ssl
模块)。因此,从密码列表中删除所有Diffie-Hellman密码,您可以解决此问题,具体取决于您的mysql服务器是否支持非Diffie-Hellman密码。以下适用于官方Python 2.7.12 amd64 win32对MySQL 5.6.17-65.0-rel65.0-log。 注意:这仅在处理模块的纯python 版本时有效。如果使用已编译的C扩展模块,则可能不接受ssl_cipher,YMMV。
import mysql.connector
import getpass
dsn = {
'database': 'INFORMATION_SCHEMA',
'host': 'mysqlserver',
'port': '3306',
'ssl_ca': '',
# ^^^ this sets cert_reqs = ssl.CERT_NONE
# in mysql/connector/network.py:415
# so no server cert verification is attempted
'use_pure': True
# setting ssl_cipher may only work with the pure python driver
# but this is the default anyway
}
dsn['user'] = raw_input('Enter Username: ')
dsn['password'] = getpass.getpass('Enter password: ')
try:
dbconn = mysql.connector.connect(**dsn)
# this will raise the 'Weak DH key' exception
except mysql.connector.errors.InterfaceError as e:
print e
dsn['ssl_cipher'] = 'HIGH:!DH:!aNULL'
# this is a standard openssl ciphersuite string
# where !DH and !aNULL means don't use any DH ciphers or null ciphers
# this option is officially undocumented
try:
dbconn = mysql.connector.connect(**dsn)
except mysql.connector.errors.InterfaceError:
raise
else:
assert isinstance(dbconn, mysql.connector.connection.MySQLConnection)
在mysql-connector-python 2.1.4中,模块源代码中的以下几行显示了它的工作原理:
mysql/connector/abstracts.py: Lines 298 - 313:
for key, value in config.items():
try:
DEFAULT_CONFIGURATION[key]
except KeyError:
raise AttributeError("Unsupported argument '{0}'".format(key))
# SSL Configuration
if key.startswith('ssl_'):
set_ssl_flag = True
self._ssl.update({key.replace('ssl_', ''): value})
else:
attribute = '_' + key
try:
setattr(self, attribute, value.strip())
except AttributeError:
setattr(self, attribute, value)
然后在mysql/connector/connection.py lines 130-134
:
if client_flags & ClientFlag.SSL and ssl_options:
packet = self._protocol.make_auth_ssl(charset=charset,
client_flags=client_flags)
self._socket.send(packet)
self._socket.switch_to_ssl(**ssl_options)
在_socket.switch_to_ssl()
:中找到 mysql/connector/network.py lines 406-421
def switch_to_ssl(self, ca, cert, key, verify_cert=False, cipher=None):
"""Switch the socket to use SSL"""
if not self.sock:
raise errors.InterfaceError(errno=2048)
try:
if verify_cert:
cert_reqs = ssl.CERT_REQUIRED
else:
cert_reqs = ssl.CERT_NONE
self.sock = ssl.wrap_socket(
self.sock, keyfile=key, certfile=cert, ca_certs=ca,
cert_reqs=cert_reqs, do_handshake_on_connect=False,
ssl_version=ssl.PROTOCOL_TLSv1, ciphers=cipher)
self.sock.do_handshake()
答案 2 :(得分:0)
出于绝望,我安装了模块 MySQL-python
并替换了连接方法,如下所示:
import MySQLdb
ssl = {
'cert': '/path/to/user.crt',
'key': '/path/to/user.key'
}
cnx = MySQLdb.connect(
host='myserver.example.com', port=3306, user='myusername',
ssl=ssl
)
......瞧瞧!我对DH没有任何问题!!它有效!!!
如果有人遇到这个问题,那么另一种解决方案是改变用于连接的模块。