Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

TLS/SSL support is vulnerable to MITM attacks #464

Closed
tiran opened this issue Apr 22, 2014 · 13 comments
Closed

TLS/SSL support is vulnerable to MITM attacks #464

tiran opened this issue Apr 22, 2014 · 13 comments
Assignees

Comments

@tiran
Copy link

tiran commented Apr 22, 2014

Pika's TLS/SSL code accepts all X.509 certificate because it doesn't verify the peer's cert at all. As consequence of this pika is vulnerable to all active attacks like man-in-the-middle attacks. An adversary can use self-signed certificate to listen to or modify all AMQP traffic. TLS without proper cert validation cancels all security of TLS.

In order to verify the peer you have to do two things:

  1. Check that the leaf certificate is signed by a trusted root certification authority. "cert_reqs=ssl.CERT_REQUIRED" enables the check. Trusted root CA certs must be loaded first.

  2. Verify that the common name (CN) or subject alternative name (SAN) DNS names matches the peer's FQDN. Python 3.x has ssl.match_hostname().

Both checks MUST be performed in order to validate the certificate correctly.

@gmr
Copy link
Member

gmr commented May 14, 2014

#1 is something that's up to the user of the client library to do. The goal is to be non-opinionated in SSL use. You basically have the full set of SSL socket options available to you.
#2 would be too opinionated to put into the core at this time.

Perhaps an example of pika with SSL using these options would be helpful in the docs?

@gmr gmr closed this as completed Jun 29, 2014
@kherrala
Copy link
Contributor

I would argue that optional support for 2) is required in core, because it is too cumbersome to override this logic. Would it be to opinionated to have hostname check in place if "cert_reqs" is set as in part 1) ? Python 2.x can be supported using https://pypi.python.org/pypi/backports.ssl_match_hostname

I can make a pull request for this change if needed.

@kherrala
Copy link
Contributor

@vitaly-krugl Any comment on this?

@vitaly-krugl
Copy link
Member

@kherrala, I will need to wrap my brain around SSL once again, before I can answer your question. Another area that pika probably doesn't support is ssl renegotiation, as pointed out in #703.

https://github.com/openwebos/libpalmsocket may be a good algorithmic reference for re-handshakes, etc. I rewrote libpalmsocket a while back, adding support for SSL renegotiation, certificates, and workarounds for a number of OpenSSL bugs.

@kherrala
Copy link
Contributor

@vitaly-krugl I have released some of the SSL patches we are currently running in production on hundreds of clients with some times poor connectivity. They can be found from my fork in master branch. These are essentially the same changes as in my previous pull request #501. Unfortunately I don't have the time to verify them on current master but they are working fine on my original fork based on Pika 0.9.14. Maybe this can be useful for you if you are intending to fix this?

From my second patch it should be obvious that MITM protection cannot be implemented using ssl_options or the current API.

I haven't looked at SSL renegotiations, but they don't seem to be a problem for us. I believe they are handled using Python socket wrapper and standard event processing automatically?

@vitaly-krugl
Copy link
Member

vitaly-krugl commented Apr 19, 2016

@gmr, would enabling the user to pass a callback to perform whatever certificate validation the user code deems necessary eliminate the issue of introducing opinionated code in pika core? The callback would be called upon completion of ssl handshake, and would have access to SSLContext.

From my past work on what is now https://github.com/openwebos/libpalmsocket, I recall apps needing a feature of this kind, as the type of validation sometimes differed from app to app. I also recall apps needing to save and reuse ssl contexts in order to speed-up SSL connection establishment a lot.

@kherrala
Copy link
Contributor

I don't see why anyone would like to override certificate name validation in HTTP clients so why would it be required here? See for example sane default behaviour found here: https://github.com/shazow/urllib3/blob/master/urllib3/connection.py

In my opinion every TLS client library should do these check at the least. This kind of MITM vulnerability would be found in a normal security audit very easily.

Another rather more opinionated suggestion is to depend on certifi (http://certifiio.readthedocs.org/en/latest/) used by the requests library.

@vitaly-krugl
Copy link
Member

@gmr, I would like to reopen this issue. I think that pika needs to provide a mechanism to enable users to configure server_hostname + context.check_hostname (server_hostname could be a switch for context.check_hostname) as well as deal with additional critical security configuration as in the excerpt from ssl.create_default_context below. My rationale follows:

I took a look at the builtin ssl.py, and see that it supplies a convenience public API function for creating contexts that represent recommended practices:

  • ssl.create_default_context(...): doc: Create a SSLContext object with default settings. NOTE: The protocol and settings may change anytime without prior deprecation. The values represent a fair balance between maximum compatibility and security.

ssl.create_default_context enables context.check_hostname = True, which will cause ssl.match_hostname to be called upon completion of the handshake in SSLSocket.do_handshake (on python 2.7, too). However, if context.check_hostname is set, then SSLSocket.do_handshake expects server_hostname to have been provided by the user, otherwise do_handshake raises ValueError.

If pika were to support check_hostname, then it would need to provide a mechanism for passing and applying server_hostname, since ssl.wrap_socket doesn't take it as an arg (at least not on python 2.7.10)

There are additional security measures that ssl.create_default_context enables that I recall from my prior experience were critical for avoiding known vulnerabilities:

    # SSLv2 considered harmful.
    context.options |= OP_NO_SSLv2

    # SSLv3 has problematic security and is only required for really old
    # clients such as IE6 on Windows XP
    context.options |= OP_NO_SSLv3

    # disable compression to prevent CRIME attacks (OpenSSL 1.0+)
    context.options |= getattr(_ssl, "OP_NO_COMPRESSION", 0)

@vitaly-krugl
Copy link
Member

vitaly-krugl commented Apr 22, 2016

Hi @gmr, I reopened this issue to keep it on our radar per rationale in #464 (comment).

I think there are changes that we can make, which would not be opinionated.

@vitaly-krugl vitaly-krugl reopened this Apr 22, 2016
@vitaly-krugl
Copy link
Member

Also, see https://www.rabbitmq.com/ssl.html

As of RabbitMQ 3.4.0, SSLv3 is disabled automatically to prevent the POODLE attack

@lukebakken lukebakken added this to the 0.12.0 milestone Jul 27, 2017
@lukebakken lukebakken self-assigned this Jul 27, 2017
@lukebakken lukebakken removed this from the 1.0.0 milestone Jan 30, 2018
geryogam added a commit to geryogam/pika that referenced this issue May 2, 2018
- ``ssl.PROTOCOL_TLSv1`` is now deprecated (https://docs.python.org/3/library/ssl.html#ssl.PROTOCOL_TLSv1), ``ssl.PROTOCOL_TLS`` should be preferred, which is used by ``ssl.create_default_context`` among other other parameters which provide a higher security level (https://docs.python.org/3/library/ssl.html#ssl.create_default_context);
- checking server hostnames prevents man in the middle attacks (pika#464);
- RabbitMQ 3.7.0 introduced a new systemctl syntax for rabbitmq.conf (https://www.rabbitmq.com/configure.html#config-file).
@vitaly-krugl
Copy link
Member

vitaly-krugl commented May 3, 2018

Note that pika is now python 2.7 + and python 2.7.9 has ssl.match_hostname(), so this wouldn't need https://pypi.python.org/pypi/backports.ssl_match_hostname

@vitaly-krugl
Copy link
Member

cc @tiran

I am closing this issue because the code in pika master now allows the application to control all the SSL features called out in the description of this issue.

In pika master targeting pika v1.0.0 release, the connection parameters support passing SSLContext and server_hostname via SSLOptions. This enables the app to control all the SSL features called out in the description of this issue. In particular:

  1. The user can set context.verify_mode = ssl.CERT_REQUIRED; and
  2. The user can set context.check_hostname = True
  • This causes SSLSocket.do_handshake() to call ssl.match_hostname(), which is supported since python 2.7.9.

@vitaly-krugl
Copy link
Member

I opened issue #1035 to make sure we have adequate test coverage for these scenarios.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants