Cyr*_* N. 5 python ssl python-3.x
我在Python中有一个通过aiosmtp接受(E)SMTP请求的代码,但是由于我在Debian 10上推送了此代码,所以我遇到了一些以前没有的错误(并且我的代码没有更改):
[SSL:NO_SHARED_CIPHER]没有共享密码(_ssl.c:1056)
SSL握手失败协议:传输:<_SelectorSocketTransport fd = 11读取=轮询写入=>
SSLError: [SSL: NO_SHARED_CIPHER] no shared cipher (_ssl.c:1056)
File "asyncio/sslproto.py", line 625, in _on_handshake_complete
raise handshake_exc
File "asyncio/sslproto.py", line 189, in feed_ssldata
self._sslobj.do_handshake()
File "ssl.py", line 763, in do_handshake
self._sslobj.do_handshake()
Run Code Online (Sandbox Code Playgroud)
和:
关闭通知后[SSL:KRB5_S_INIT]应用程序数据(_ssl.c:2609)
数据接收协议中的SSL错误:传输:<_SelectorSocketTransport fd = 15读取=轮询写入=>
SSLError: [SSL: KRB5_S_INIT] application data after close notify (_ssl.c:2609)
File "asyncio/sslproto.py", line 526, in data_received
ssldata, appdata = self._sslpipe.feed_ssldata(data)
File "asyncio/sslproto.py", line 207, in feed_ssldata
self._sslobj.unwrap()
File "ssl.py", line 767, in unwrap
return self._sslobj.shutdown()
Run Code Online (Sandbox Code Playgroud)
我认为这两个问题是相关的。
不幸的是,两个stacktrace没有显示与我的代码相关的任何内容,这使我很难更好地了解发生了什么,并且该异常与另一个异常(Python3)不相关。
这是我的软件包的版本:
uname -a: Linux my-server 4.19.0-5-amd64 #1 SMP Debian 4.19.37-5+deb10u2 (2019-08-08) x86_64 GNU/Linux
python --version: Python 3.7.3
点冻结
aiomysql==0.0.20
aiosmtpd==1.2
asn1crypto==0.24.0
atpublic==1.0
authres==1.2.0
beanstalkc3==0.4.0
blinker==1.4
certifi==2018.8.24
cffi==1.12.3
chardet==3.0.4
Click==7.0
cloud-init==18.3
configobj==5.0.6
cryptography==2.6.1
distro-info==0.21
dkimpy==0.9.4
dnspython==1.16.0
fail2ban==0.10.2
Flask==1.1.1
idna==2.6
itsdangerous==1.1.0
Jinja2==2.10.1
jsonpatch==1.21
jsonpointer==1.10
jsonschema==2.6.0
MarkupSafe==1.1.0
mysqlclient==1.4.4
oauthlib==2.1.0
psutil==5.6.3
py3dns==3.2.1
pycparser==2.19
PyGObject==3.30.4
pyinotify==0.9.6
PyJWT==1.7.0
PyMySQL==0.9.2
PyNaCl==1.3.0
pyspf==2.0.13
pysrs==1.0.3
python-apt==1.8.4
python-dotenv==0.10.3
PyYAML==3.13
requests==2.21.0
sentry-sdk==0.12.3
six==1.12.0
systemd-python==234
unattended-upgrades==0.1
urllib3==1.24.1
uWSGI==2.0.18
Werkzeug==0.16.0
Run Code Online (Sandbox Code Playgroud)
我相信,如果我的代码出了点问题,那么我在Debian 9和更早版本中会遇到这个错误,而我从未遇到过。
我在SO和Google上搜索了此错误,但没有找到任何东西。我怀疑特定项目的特定版本(aiosmtpd,async或python)存在一些问题,但没有任何线索。
我希望你能帮助我:)
更新:
我在通信中添加了对密码的跟踪。共享密码为:
[[TLS_AES_256_GCM_SHA384, TLSv1.3, 256], [TLS_CHACHA20_POLY1305_SHA256, TLSv1.3, 256], [TLS_AES_128_GCM_SHA256, TLSv1.3, 128], [ECDHE-ECDSA-AES256-GCM-SHA384, TLSv1.2, 256], [ECDHE-RSA-AES256-GCM-SHA384, TLSv1.2, 256], [DHE-RSA-AES256-GCM-SHA384, TLSv1.2, 256], [ECDHE-ECDSA-CHACHA20-POLY1305, TLSv1.2, 256], [ECDHE-RSA-CHACHA20-POLY1305, TLSv1.2, 256], [DHE-RSA-CHACHA20-POLY1305, TLSv1.2, 256], [ECDHE-ECDSA-AES128-GCM-SHA256, TLSv1.2, 128], [ECDHE-RSA-AES128-GCM-SHA256, TLSv1.2, 128]]
Run Code Online (Sandbox Code Playgroud)
套接字的密码是:[ECDHE-RSA-AES256-GCM-SHA384, TLSv1.2, 256]这在共享密码中。
更新2
我可以重现该错误,但只能在特定条件下进行。
在新服务器上,这是我运行的代码:
import asyncio, logging, sys, signal, ssl
from aiosmtpd.controller import Controller
from aiosmtpd.handlers import Debugging
from aiosmtpd.smtp import SMTP
class ControllerTls(Controller):
def factory(self):
context = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH)
context.load_cert_chain('./certs/certificate.pem', './certs/id_rsa')
context.load_dh_params('./certs/dhparams.pem')
return SMTP(
self.handler,
tls_context=context
)
# Temporary outputing errors from mail.log
streamHandler = logging.StreamHandler(sys.stdout)
streamHandler.setFormatter(logging.Formatter('[%(asctime)-15s] (%(levelname)s) - %(message)s'))
streamHandler.setLevel(logging.INFO)
maillog = logging.getLogger('mail.log')
maillog.setLevel(logging.INFO)
maillog.addHandler(streamHandler)
controller = ControllerTls(Debugging(), hostname='0.0.0.0', port=2125)
controller.start()
print('Controller started!')
sig = signal.sigwait([signal.SIGINT, signal.SIGQUIT])
controller.stop()
Run Code Online (Sandbox Code Playgroud)
这是一个基本脚本,可以帮助我重现此问题。
在旧服务器上,我运行以下代码:
import smtplib, ssl, sys
port = 25
if len(sys.argv) == 3:
port = sys.argv[2]
def com(client, command, *args, **kwargs):
result = getattr(client, command)(*args, **kwargs)
if result[0] > 500:
print('[FATAL] - An error occured!')
print(result)
client.quit()
exit()
context = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH)
context.load_cert_chain('/var/www/towboat/certs/certificate.pem', '/var/www/towboat/certs/id_rsa')
context.set_ciphers('ECDHE-ECDSA-AES256-GCM-SHA384')
client = smtplib.SMTP(sys.argv[1], port=port)
com(client, 'ehlo')
com(client, 'starttls', context=context)
com(client, 'ehlo')
com(client, 'mail', 'contact@improvmx.com')
com(client, 'rcpt', 'cyril@improvmx.com')
com(client, 'quit')
print('All good !')
Run Code Online (Sandbox Code Playgroud)
我打电话给:
sendmail.py {ip.of.new.server} 2125
在旧服务器(运行脚本的服务器)上,出现此错误:
Controller started!
[2019-10-08 15:57:11,878] (INFO) - Peer: ('ip.of.old.server', 45492)
[2019-10-08 15:57:11,878] (INFO) - ('ip.of.old.server', 45492) handling connection
[2019-10-08 15:57:11,880] (INFO) - ('ip.of.old.server', 45492) Data: b'ehlo {name old server}'
[2019-10-08 15:57:11,883] (INFO) - ('ip.of.old.server', 45492) Data: b'STARTTLS'
[2019-10-08 15:57:11,883] (INFO) - ('ip.of.old.server', 45492) STARTTLS
SSL handshake failed
protocol: <asyncio.sslproto.SSLProtocol object at 0x7f04d33d7d30>
transport: <_SelectorSocketTransport fd=7 read=polling write=<idle, bufsize=0>>
Traceback (most recent call last):
File "/usr/lib/python3.7/asyncio/sslproto.py", line 625, in _on_handshake_complete
raise handshake_exc
File "/usr/lib/python3.7/asyncio/sslproto.py", line 189, in feed_ssldata
self._sslobj.do_handshake()
File "/usr/lib/python3.7/ssl.py", line 763, in do_handshake
self._sslobj.do_handshake()
ssl.SSLError: [SSL: NO_SHARED_CIPHER] no shared cipher (_ssl.c:1056)
SSL error in data received
protocol: <asyncio.sslproto.SSLProtocol object at 0x7f04d33d7d30>
transport: <_SelectorSocketTransport closing fd=7 read=idle write=<idle, bufsize=0>>
Traceback (most recent call last):
File "/usr/lib/python3.7/asyncio/sslproto.py", line 526, in data_received
ssldata, appdata = self._sslpipe.feed_ssldata(data)
File "/usr/lib/python3.7/asyncio/sslproto.py", line 189, in feed_ssldata
self._sslobj.do_handshake()
File "/usr/lib/python3.7/ssl.py", line 763, in do_handshake
self._sslobj.do_handshake()
ssl.SSLError: [SSL: NO_SHARED_CIPHER] no shared cipher (_ssl.c:1056)
[2019-10-08 15:58:33,909] (INFO) - Connection lost during _handle_client()
Run Code Online (Sandbox Code Playgroud)
超级奇怪的是,如果我在本地计算机上复制sendmail脚本,然后将其运行指向新服务器,那么我将不再有错误!
(因此问题必须与旧服务器有关?但是为什么新服务器显示异常?!)
如果我切换脚本(测试从新服务器向旧服务器发送电子邮件),则可以正常工作...
我认为原因是这样的:
新服务器上为 v1.1.1d,旧服务器上为 1.1.0d
1.1.1行引入了TLSv3和许多其他相当重要的更改 -请参阅更改日志。
正如我看到您在aiosmtpd github上开票一样,您已经正确猜测到您收到错误的原因是 aiosmtpd。原因是它支持You need at least Python 3.5,它不支持openssl 1.1.1。目前只有python 3.7(甚至还没有完全向后移植到python 3.6)支持openssl 1.1.1。
由于aiosmtpd的最新版本是1.2 (2018-09-01),因此可以假设(没有看到任何PR)他们尚未实现新的 openssl 1.1.1 [2018 年 9 月 11 日]带来了重大变化。
除了为aiosmtpd提供 PR 之外,您唯一的选择是将openssl降级到1.1.0 系列的最新版本(当前为1.1.0i )。