How to block SSL protocols in favor of TLS?

前端 未结 2 1858
广开言路
广开言路 2020-12-04 00:15

How can I block SSL protocols in PyOpenSSL in favour of TLS? I\'m using CentOS 7 and have these versions:

pyOpenSSL-0.         


        
相关标签:
2条回答
  • 2020-12-04 00:23

    There are two ways to do it I am aware. One is a configuratio options, and the other is a runtime option.

    Configuration Option

    The configuration option is used when building OpenSSL. Its great for all applications because it applies your administrative policy and addresses applications which are not mindful to SSL/TLS related issues.

    For this option, simply configure OpenSSL with no-ssl2 no-ssl3. no-comp is also often used because compression can leak information.

    ./Configure no-ssl2 no-ssl3 <other opts>
    

    Other OpenSSL options are available, and you might want to visit Compilation and Installation on OpenSSL's wiki.

    Runtime Option

    In C, you have to (1) use the 2/3 method to get SSL 2/3 and above; and then (2) call SSL_CTX_set_options (or SSL_set_options) and (3) remove the SSL protocols. That leaves the TLS protocols:

    SSL_CTX* ctx = SSL_CTX_new(SSLv23_method());
    const long flags = SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_NO_COMPRESSION;
    SSL_CTX_set_options(ctx, flags);
    

    In Python, you do it with OpenSSL.SSL.Context.set_options.

    0 讨论(0)
  • 2020-12-04 00:32

    This is really good question for CherryPy today. This month we started discussing SSL issues and overall maintainability of CherryPy's wrappers over py2.6+ ssl and pyOpenSSL in CherryPy user group. I'm planning a topic about SSL issues there, so you can subscribe for the group to get more details later.

    For now, here's what is possible. I had Debian Wheezy, Python 2.7.3-4+deb7u1, OpenSSL 1.0.1e-2+deb7u16. I've installed CherryPy from the repo (3.6 has broken SSL), and pyOpenSSL 0.14. I tried to override both CherryPy SSL adapters to gain some points in Qualys SSL labs test. It is very helpful and I strongly suggest you to test your deployment with it (whatever is your frontend, CherryPy or not).

    As a result, ssl-based adapter still has vulnerabilities which I don't see the way to workaround in py2 < 2.7.9 (massive SSL update) and py3 < 3.3. Because CherryPy ssl adapter was written long before these changes, it needs a rewrite to support both old and new ways (mostly SSL Contexts). On the other hand with subclassed pyOpenSSL adapted it's mostly fine, except for:

    • Enabled Secure Client-Initiated Renegotiation. It may be OpenSSL-dependent.
    • no Forward Secrecy, SSL.OP_SINGLE_DH_USE could have helped but it didn't. May also depend on version of OpenSSL.

    Here's the code.

    #!/usr/bin/env python
    # -*- coding: utf-8 -*-
    
    
    import os
    import sys
    import ssl
    
    import cherrypy
    from cherrypy.wsgiserver.ssl_builtin import BuiltinSSLAdapter
    from cherrypy.wsgiserver.ssl_pyopenssl import pyOpenSSLAdapter
    
    from cherrypy import wsgiserver
    if sys.version_info < (3, 0):
      from cherrypy.wsgiserver.wsgiserver2 import ssl_adapters  
    else:
      from cherrypy.wsgiserver.wsgiserver3 import ssl_adapters
    
    try:
      from OpenSSL import SSL
    except ImportError:
      pass
    
    
    ciphers = (
      'ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:DH+AES:ECDH+HIGH:'
      'DH+HIGH:ECDH+3DES:DH+3DES:RSA+AESGCM:RSA+AES:RSA+HIGH:RSA+3DES:!aNULL:'
      '!eNULL:!MD5:!DSS:!RC4:!SSLv2'
    )
    
    bundle = os.path.join(os.path.dirname(cherrypy.__file__), 'test', 'test.pem')
    
    config = {
      'global' : {
        'server.socket_host' : '127.0.0.1',
        'server.socket_port' : 8443,
        'server.thread_pool' : 8,
    
        'server.ssl_module'      : 'custom-pyopenssl',
        'server.ssl_certificate' : bundle,
        'server.ssl_private_key' : bundle,
      }
    }
    
    
    class BuiltinSsl(BuiltinSSLAdapter):
      '''Vulnerable, on py2 < 2.7.9, py3 < 3.3:
        * POODLE (SSLv3), adding ``!SSLv3`` to cipher list makes it very incompatible
        * can't disable TLS compression (CRIME)
        * supports Secure Client-Initiated Renegotiation (DOS)
        * no Forward Secrecy
      Also session caching doesn't work. Some tweaks are posslbe, but don't really 
      change much. For example, it's possible to use ssl.PROTOCOL_TLSv1 instead of 
      ssl.PROTOCOL_SSLv23 with little worse compatiblity.
      '''
    
      def wrap(self, sock):
        """Wrap and return the given socket, plus WSGI environ entries."""
        try:
          s = ssl.wrap_socket(
            sock, 
            ciphers = ciphers, # the override is for this line
            do_handshake_on_connect = True,
            server_side = True, 
            certfile = self.certificate,
            keyfile = self.private_key,
            ssl_version = ssl.PROTOCOL_SSLv23
          )
        except ssl.SSLError:
          e = sys.exc_info()[1]
          if e.errno == ssl.SSL_ERROR_EOF:
            # This is almost certainly due to the cherrypy engine
            # 'pinging' the socket to assert it's connectable;
            # the 'ping' isn't SSL.
            return None, {}
          elif e.errno == ssl.SSL_ERROR_SSL:
            if e.args[1].endswith('http request'):
              # The client is speaking HTTP to an HTTPS server.
              raise wsgiserver.NoSSLError
            elif e.args[1].endswith('unknown protocol'):
              # The client is speaking some non-HTTP protocol.
              # Drop the conn.
              return None, {}
          raise
    
        return s, self.get_environ(s)
    
    ssl_adapters['custom-ssl'] = BuiltinSsl
    
    
    class Pyopenssl(pyOpenSSLAdapter):
      '''Mostly fine, except:
        * Secure Client-Initiated Renegotiation
        * no Forward Secrecy, SSL.OP_SINGLE_DH_USE could have helped but it didn't
      '''
    
      def get_context(self):
        """Return an SSL.Context from self attributes."""
        c = SSL.Context(SSL.SSLv23_METHOD)
    
        # override:
        c.set_options(SSL.OP_NO_COMPRESSION | SSL.OP_SINGLE_DH_USE | SSL.OP_NO_SSLv2 | SSL.OP_NO_SSLv3)
        c.set_cipher_list(ciphers)
    
        c.use_privatekey_file(self.private_key)
        if self.certificate_chain:
            c.load_verify_locations(self.certificate_chain)
        c.use_certificate_file(self.certificate)
        return c
    
    ssl_adapters['custom-pyopenssl'] = Pyopenssl
    
    
    class App:
    
      @cherrypy.expose
      def index(self):
        return '<em>Is this secure?</em>'
    
    
    if __name__ == '__main__':
      cherrypy.quickstart(App(), '/', config)
    

    Update

    Here's the article and discussion where future of CherryPy's SSL support should be decided.

    0 讨论(0)
提交回复
热议问题