¿Cómo bloquear los protocolos SSL a favor de TLS?

¿Cómo puedo bloquear los protocolos SSL en PyOpenSSL a favor de TLS ? Estoy usando CentOS 7 y tengo estas versiones:

 pyOpenSSL-0.13.1-3.el7.x86_64 openssl-1.0.1e-34.el7_0.7.x86_64 

En mi archivo de configuración (esto si es para una aplicación CherryPy) tengo:

 'server.ssl_module': 'pyopenssl', 

Esta es una muy buena pregunta para CherryPy hoy. Este mes comenzamos a discutir los problemas de SSL y la capacidad de mantenimiento general de las envolturas de CherryPy sobre py2.6 + ssl y pyOpenSSL en el grupo de usuarios de CherryPy . Estoy planeando un tema sobre problemas de SSL allí, para que pueda suscribirse al grupo para obtener más detalles más adelante.

Por ahora, esto es lo que es posible. Tuve Debian Wheezy, Python 2.7.3-4 + deb7u1, OpenSSL 1.0.1e-2 + deb7u16. He instalado CherryPy desde el repository (3.6 ha roto SSL), y pyOpenSSL 0.14. Intenté anular ambos adaptadores SSL de CherryPy para obtener algunos puntos en la prueba de laboratorio SSL de Qualys. Es muy útil y le sugiero encarecidamente que pruebe su implementación con él (sea cual sea su interfaz, sea CherryPy o no).

Como resultado, el adaptador basado en ssl todavía tiene vulnerabilidades que no veo la forma de solucionar en py2 <2.7.9 (actualización masiva de SSL) y py3 <3.3. Debido a que el adaptador CherryPy ssl se escribió mucho antes de estos cambios, necesita una reescritura para admitir formas antiguas y nuevas (en su mayoría, Contextos SSL ). Por otro lado, con una adaptación PyOpenSSL subclasificada, está muy bien, excepto por:

  • Habilitación de la renegociación iniciada por el cliente seguro . Puede ser dependiente de OpenSSL.
  • no Reenviar Secreto , SSL.OP_SINGLE_DH_USE podría haber ayudado pero no lo hizo. También puede depender de la versión de OpenSSL.

Aquí está el código.

 #!/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 'Is this secure?' if __name__ == '__main__': cherrypy.quickstart(App(), '/', config) 

Actualizar

Aquí está el artículo y la discusión donde se decidirá el futuro de la compatibilidad con SSL de CherryPy.

Hay dos maneras de hacerlo, estoy consciente. Una es una opción de configuración, y la otra es una opción de tiempo de ejecución.

Opción de configuración

La opción de configuración se utiliza al construir OpenSSL. Es ideal para todas las aplicaciones porque aplica su política administrativa y aborda aplicaciones que no son conscientes de los problemas relacionados con SSL / TLS.

Para esta opción, simplemente configure OpenSSL con no-ssl2 no-ssl3 . no-comp también se usa a menudo porque la compresión puede filtrar información.

 ./Configure no-ssl2 no-ssl3  

Hay otras opciones de OpenSSL disponibles y es posible que desee visitar Comstackción e instalación en la wiki de OpenSSL.

Opción de tiempo de ejecución

En C, debe (1) usar el método 2/3 para obtener SSL 2/3 y superior; y luego (2) llame a SSL_CTX_set_options (o SSL_set_options ) y (3) elimine los protocolos SSL. Eso deja los protocolos TLS:

 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); 

En Python, lo haces con OpenSSL.SSL.Context.set_options .