python / asyncio

asyncio historical repository
https://docs.python.org/3/library/asyncio.html
1.04k stars 177 forks source link

SSL socket exhaustion? #483

Open kyuupichan opened 7 years ago

kyuupichan commented 7 years ago

I have written a fairly widely used server, ElectrumX, with asyncio. This issue

https://github.com/kyuupichan/electrumx/issues/94

is essentially about clients that connect to the SSL port and then do nothing during the SSL handshake. The number of connections doing this seems to gradually increase over time. It is easily confirmed these never time out by simply making a telnet connection to the SSL port and doing nothing.

An SSL server created with create_server() creates protocols using the protocol factory when the initial connection comes in, but because of the socket wrapping it will not call connection_made() until the handshake is complete. As a result it seems I have no way of getting the socket or the transport of these ghost connections, and therefore I cannot close them if stale. I also don't see anywhere I can specify SSL handshake timeouts in asyncio.

I've looked over the code and pored over the docs, but cannot find anything about this. Am I missing something obvious?

kyuupichan commented 7 years ago

This would seem to be an easy avenue to exhaust the open file limit of any asyncio server that accepts SSL connections as it is out of the control of the application author.

Should there not be some timeout on SSL handshakes - both initial handshake and shutdown handshake?

Martiusweb commented 7 years ago

Hi,

I didn't dig too deep, but it think that's indeed an issue which should be fixed: it's probably easy to DOS an asyncio server by keeping SSL connections open without completing the handshake. We don't need to do anything for client SSL streams, wrapping open_connection() (or the equivalent for other streams) in wait_for() with a timeout is sufficient.

I'm interested in working on this. The simplest solution is probably to set a timeout on idle streams. We have to keep in mind that either solution must work for any kind of stream transport.

I can look at how we can update the API to include a timeout argument to the right methods and coroutine functions.

kyuupichan commented 7 years ago

Any progress on this? This is a huge flaw for asyncio SSL servers in a hostile environment.

fafhrd91 commented 7 years ago

here is fix https://github.com/python/cpython/pull/480

kyuupichan commented 7 years ago

Fantastic, thank you. I hope this can be back-ported to 3.5.x and 3.6.x.

fafhrd91 commented 7 years ago

fix is trivial, we can include it into aiohttp for old python versions.

kyuupichan commented 7 years ago

aiohttp? Not using that; using simple SSL sockets with raw TCP

fafhrd91 commented 7 years ago

ah, ok. just saw aiohttp in install_requires. then you can do monkey patch yourself.

kyuupichan commented 7 years ago

Well I can for myself, but not for my 100 users. As this is a remotely exploitable resource leakage I think it should be backported.

fafhrd91 commented 7 years ago

I mean fix should be included in library that you use. and sure it should be backported, but this will take some time.