2009-06-24 16 views
19

Estoy usando el SSLSocket de Java para asegurar las comunicaciones entre un cliente y un programa de servidor. El programa de servidor también sirve solicitudes HTTPS desde navegadores web.¿Qué suites de cifrado habilitar para SSL Socket?

Según "Beginning Cryptography with Java", página 371, siempre debe llamar setEnabledCipherSuites en su SSLSocket/SSLServerSocket para asegurar que el conjunto de cifrado que termina siendo negociado es lo suficientemente fuerte para sus propósitos.

Dicho esto, una llamada al método getDefaultCipherSuites mi SSLSocketFactory 's produce algunos opciones. Estas opciones van desde TLS_RSA_WITH_AES_256_CBC_SHA (que creo que es bastante seguro) hasta SSL_RSA_WITH_RC4_128_MD5 (no estoy seguro si eso es seguro, dado el estado actual de MD5) a SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA (no del todo seguro de lo que hace).

¿Cuál es una lista sensata de suites de cifrado para restringir los enchufes?

Tenga en cuenta que el cliente y el servidor tienen acceso al proveedor de servicios Bouncy Castle, y que pueden tener o no archivos ilimitados de política criptográfica instalados.

+0

'TLS_RSA_WITH_AES_256_CBC_SHA' ... - probablemente debería evitar los sistemas de transporte de claves RSA (o colocarlos en la parte inferior de la lista anunciada) En su lugar, favorezca los intercambios de claves efímeras, como 'DHE', para mantener el secreto hacia adelante. De hecho, TLS 1.3 está discutiendo su eliminación porque carecen de la propiedad. – jww

+0

'SSL_RSA_WITH_RC4_128_MD5' ... -' RC4' es el hijo problemático ahora. Ver [Sobre la seguridad de RC4 en TLS y WPA] (http://www.isg.rhul.ac.uk/tls/). Un atacante probablemente * no puede * falsificar una firma 'HMAC-MD5' en la ventana de tiempo 2MSL de la red. Sin embargo, un atacante puede correlacionar estadísticamente bits en la secuencia de cifrado. (Y MD5 * está * muerto para uso a largo plazo, como certificados y firmas digitales). – jww

+0

'SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA' ... - grabarlo. Evítalo como la peste. – jww

Respuesta

7

No utilice nada con la exportación en él. Eso es crippleware debido a las restricciones de exportación en la criptografía fuerte.

EDITAR: Se modificó para usar el documento de 2009.

Un 2009 NIST recommendation enumera los siguientes, incluing TLS_RSA_WITH_AES_256_CBC_SHA (que usted ha mencionado):

TLS_RSA_WITH_NULL_SHA (no utilice esto a menos que esté seguro de que no es necesario ninguna privacidad/confidencialidad).

TLS_RSA_WITH_3DES_EDE_CBC_SHA 
TLS_RSA_WITH_AES_128_CBC_SHA 
TLS_RSA_WITH_AES_256_CBC_SHA 
TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA 
TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA 
TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA 
TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA 
TLS_DH_DSS_WITH_AES_128_CBC_SHA 
TLS_DH_RSA_WITH_AES_128_CBC_SHA 
TLS_DHE_DSS_WITH_AES_128_CBC_SHA 
TLS_DHE_RSA_WITH_AES_128_CBC_SHA 
TLS_DH_DSS_WITH_AES_256_CBC_SHA 
TLS_DH_RSA_WITH_AES_256_CBC_SHA 
TLS_DHE_DSS_WITH_AES_256_CBC_SHA 
TLS_DHE_RSA_WITH_AES_256_CBC_SHA 
TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA 
TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA 
TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA 
TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA 
TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA 
TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA 
TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA 
TLS_ECDH_RSA_WITH_AES_128_CBC_SHA 
TLS_ECDH_RSA_WITH_AES_256_CBC_SHA 
TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA 
TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA 
TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA 
TLS_PSK_WITH_3DES_EDE_CBC_SHA 
TLS_PSK_WITH_AES_128_CBC_SHA 
TLS_PSK_WITH_AES_256_CBC_SHA 
TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA 
TLS_DHE_PSK_WITH_AES_128_CBC_SHA 
TLS_DHE_PSK_WITH_AES_256_CBC_SHA 
TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA 
TLS_RSA_PSK_WITH_AES_128_CBC_SHA 
TLS_RSA_PSK_WITH_AES_256_CBC_SHA 
TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 
TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 
TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 
TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 
+3

Estoy un poco confundido acerca de TLS_RSA_WITH_NULL_SHA - ¿eso no especifica ningún cifrado? En este contexto, ¿esto significa * no * o * cualquier * encriptación? – Zarkonnen

+2

Zarkonnen, creo que tiene razón en que TLS_RSA_WITH_NULL_SHA significa que no hay encriptación. pag. 34 del borrador al que he vinculado dice que el cifrado NULL es para "casos en los que se requiere protección de integridad pero no cifrado". –

+1

Dudo que necesite claves de clave previamente compartida (PSK) como 'TLS_PSK_WITH_3DES_EDE_CBC_SHA'. 'TLS_RSA_WITH_AES_256_CBC_SHA' utiliza el transporte de claves RSA. Probablemente debería estar usando 'DHE' o' ECDHE' para mantener el secreto. – jww

15

A continuación se muestra la clase de Java que utilizo para hacer cumplir las suites de cifrado y los protocolos. Antes de SSLSocketFactoryEx, estaba modificando las propiedades en el SSLSocket cuando tenía acceso a ellas. La gente de Java en Stack Overflow lo ayudó, así que es bueno poder publicarlo aquí.

SSLSocketFactoryEx prefiere paquetes de cifrado más fuertes (como ECDHE y DHE), y se omite conjuntos de cifrado débiles y heridos (como RC4 y MD5). Tiene que habilitar cuatro cifras de transporte de clave RSA para la interoperabilidad con Google y Microsoft cuando TLS 1.2 es no disponible. Son TLS_RSA_WITH_AES_256_CBC_SHA256, TLS_RSA_WITH_AES_256_CBC_SHA y dos amigos. Si es posible, debe eliminar los esquemas de transporte de claves TLS_RSA_*.

Mantenga la lista de la suite de cifrado lo más pequeña posible. Si anuncia todos los cifrados disponibles (similar a la lista de Flaschen), entonces su lista será 80+. Eso ocupa 160 bytes en el ClientHello, y puede hacer que algunos dispositivos fallen porque tienen un pequeño búfer de tamaño fijo para procesar el ClientHello. Los dispositivos rotos incluyen F5 y Ironport.

En la práctica, la lista del código siguiente se vincula a 10 o 15 suites de cifrado una vez que la lista preferida se cruza con las suites de cifrado admitidas por Java. Por ejemplo, esta es la lista que recibo cuando me preparo para conectarme o microsoft.com o google.com con una política ilimitada JCE en su lugar:

  • TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384
  • TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384
  • TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256
  • TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256
  • TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
  • TLS_DHE_DSS_WITH_AES_256_GCM_SHA384
  • TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA25 6
  • TLS_DHE_DSS_WITH_AES_128_GCM_SHA256
  • TLS_DHE_DSS_WITH_AES_256_CBC_SHA256
  • TLS_DHE_RSA_WITH_AES_128_CBC_SHA
  • TLS_DHE_DSS_WITH_AES_128_CBC_SHA
  • TLS_RSA_WITH_AES_256_CBC_SHA256
  • TLS_RSA_WITH_AES_256_CBC_SHA
  • TLS_RSA_WITH_AES_128_CBC_SHA256
  • TLS_RSA_WITH_AES_128_CBC_SHA

La lista omite algoritmos débiles/heridos, como RC4 y MD5. Si están habilitados, es probable que obtenga un Obsolete cryptography warning from Browser en alguna ocasión.

La lista será más pequeña con la política de JCE predeterminada porque la política elimina AES-256 y algunos otros. Creo que se trata de 7 suites de cifrado con la política restringida.

La clase SSLSocketFactoryEx también garantiza que se utilizan protocolos TLS 1.0 y superiores. Los clientes Java anteriores a Java 8 deshabilitan TLS 1.1 y 1.2. SSLContext.getInstance("TLS") también se colarán en SSLv3 (incluso en Java 8), por lo que hay que tomar medidas para eliminarlo.

Finalmente, la clase a continuación es compatible con TLS 1.3, por lo que debería funcionar cuando el proveedor los ponga a disposición. Las suites de cifrado *_CHACHA20_POLY1305 son preferibles si están disponibles porque son mucho más rápidas que algunas de las suites actuales y tienen mejores propiedades de seguridad. Google ya lo implementó en sus servidores. No estoy seguro de cuándo Oracle los proporcionará. OpenSSL les proporcionará OpenSSL 1.0.2 1.1.0.

Se puede utilizar de este modo:

URL url = new URL("https://www.google.com:443"); 
HttpsURLConnection connection = (HttpsURLConnection) url.openConnection(); 

SSLSocketFactoryEx factory = new SSLSocketFactoryEx(); 
connection.setSSLSocketFactory(factory); 
connection.setRequestProperty("charset", "utf-8"); 

InputStream input = connection.getInputStream(); 
InputStreamReader reader = new InputStreamReader(input, "utf-8"); 
BufferedReader buffer = new BufferedReader(reader); 
... 

class SSLSocketFactoryEx extends SSLSocketFactory 
{ 
    public SSLSocketFactoryEx() throws NoSuchAlgorithmException, KeyManagementException 
    { 
     initSSLSocketFactoryEx(null,null,null); 
    } 

    public SSLSocketFactoryEx(KeyManager[] km, TrustManager[] tm, SecureRandom random) throws NoSuchAlgorithmException, KeyManagementException 
    { 
     initSSLSocketFactoryEx(km, tm, random); 
    } 

    public SSLSocketFactoryEx(SSLContext ctx) throws NoSuchAlgorithmException, KeyManagementException 
    { 
     initSSLSocketFactoryEx(ctx); 
    } 

    public String[] getDefaultCipherSuites() 
    { 
     return m_ciphers; 
    } 

    public String[] getSupportedCipherSuites() 
    { 
     return m_ciphers; 
    } 

    public String[] getDefaultProtocols() 
    { 
     return m_protocols; 
    } 

    public String[] getSupportedProtocols() 
    { 
     return m_protocols; 
    } 

    public Socket createSocket(Socket s, String host, int port, boolean autoClose) throws IOException 
    { 
     SSLSocketFactory factory = m_ctx.getSocketFactory(); 
     SSLSocket ss = (SSLSocket)factory.createSocket(s, host, port, autoClose); 

     ss.setEnabledProtocols(m_protocols); 
     ss.setEnabledCipherSuites(m_ciphers); 

     return ss; 
    } 

    public Socket createSocket(InetAddress address, int port, InetAddress localAddress, int localPort) throws IOException 
    { 
     SSLSocketFactory factory = m_ctx.getSocketFactory(); 
     SSLSocket ss = (SSLSocket)factory.createSocket(address, port, localAddress, localPort); 

     ss.setEnabledProtocols(m_protocols); 
     ss.setEnabledCipherSuites(m_ciphers); 

     return ss; 
    } 

    public Socket createSocket(String host, int port, InetAddress localHost, int localPort) throws IOException 
    { 
     SSLSocketFactory factory = m_ctx.getSocketFactory(); 
     SSLSocket ss = (SSLSocket)factory.createSocket(host, port, localHost, localPort); 

     ss.setEnabledProtocols(m_protocols); 
     ss.setEnabledCipherSuites(m_ciphers); 

     return ss; 
    } 

    public Socket createSocket(InetAddress host, int port) throws IOException 
    { 
     SSLSocketFactory factory = m_ctx.getSocketFactory(); 
     SSLSocket ss = (SSLSocket)factory.createSocket(host, port); 

     ss.setEnabledProtocols(m_protocols); 
     ss.setEnabledCipherSuites(m_ciphers); 

     return ss; 
    } 

    public Socket createSocket(String host, int port) throws IOException 
    { 
     SSLSocketFactory factory = m_ctx.getSocketFactory(); 
     SSLSocket ss = (SSLSocket)factory.createSocket(host, port); 

     ss.setEnabledProtocols(m_protocols); 
     ss.setEnabledCipherSuites(m_ciphers); 

     return ss; 
    } 

    private void initSSLSocketFactoryEx(KeyManager[] km, TrustManager[] tm, SecureRandom random) 
    throws NoSuchAlgorithmException, KeyManagementException 
    { 
     m_ctx = SSLContext.getInstance("TLS"); 
     m_ctx.init(km, tm, random); 

     m_protocols = GetProtocolList(); 
     m_ciphers = GetCipherList(); 
    } 

    private void initSSLSocketFactoryEx(SSLContext ctx) 
    throws NoSuchAlgorithmException, KeyManagementException 
    { 
     m_ctx = ctx; 

     m_protocols = GetProtocolList(); 
     m_ciphers = GetCipherList(); 
    } 

    protected String[] GetProtocolList() 
    { 
     String[] preferredProtocols = { "TLSv1", "TLSv1.1", "TLSv1.2", "TLSv1.3" }; 
     String[] availableProtocols = null; 

     SSLSocket socket = null; 

     try 
     { 
      SSLSocketFactory factory = m_ctx.getSocketFactory(); 
      socket = (SSLSocket)factory.createSocket(); 

      availableProtocols = socket.getSupportedProtocols(); 
      Arrays.sort(availableProtocols); 
     } 
     catch(Exception e) 
     { 
      return new String[]{ "TLSv1" }; 
     } 
     finally 
     { 
      if(socket != null) 
       socket.close(); 
     } 

     List<String> aa = new ArrayList<String>(); 
     for(int i = 0; i < preferredProtocols.length; i++) 
     { 
      int idx = Arrays.binarySearch(availableProtocols, preferredProtocols[i]); 
      if(idx >= 0) 
       aa.add(preferredProtocols[i]); 
     } 

     return aa.toArray(new String[0]); 
    } 

    protected String[] GetCipherList() 
    { 
     String[] preferredCiphers = { 

      // *_CHACHA20_POLY1305 are 3x to 4x faster than existing cipher suites. 
      // http://googleonlinesecurity.blogspot.com/2014/04/speeding-up-and-strengthening-https.html 
      // Use them if available. Normative names can be found at (TLS spec depends on IPSec spec): 
      // http://tools.ietf.org/html/draft-nir-ipsecme-chacha20-poly1305-01 
      // http://tools.ietf.org/html/draft-mavrogiannopoulos-chacha-tls-02 
      "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305", 
      "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305", 
      "TLS_ECDHE_ECDSA_WITH_CHACHA20_SHA", 
      "TLS_ECDHE_RSA_WITH_CHACHA20_SHA", 

      "TLS_DHE_RSA_WITH_CHACHA20_POLY1305", 
      "TLS_RSA_WITH_CHACHA20_POLY1305", 
      "TLS_DHE_RSA_WITH_CHACHA20_SHA", 
      "TLS_RSA_WITH_CHACHA20_SHA", 

      // Done with bleeding edge, back to TLS v1.2 and below 
      "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384", 
      "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384", 
      "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256", 
      "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256", 

      "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384", 
      "TLS_DHE_DSS_WITH_AES_256_GCM_SHA384", 
      "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", 
      "TLS_DHE_DSS_WITH_AES_128_GCM_SHA256", 

      // TLS v1.0 (with some SSLv3 interop) 
      "TLS_DHE_RSA_WITH_AES_256_CBC_SHA384", 
      "TLS_DHE_DSS_WITH_AES_256_CBC_SHA256", 
      "TLS_DHE_RSA_WITH_AES_128_CBC_SHA", 
      "TLS_DHE_DSS_WITH_AES_128_CBC_SHA", 

      "TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA", 
      "TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA", 
      "SSL_DH_RSA_WITH_3DES_EDE_CBC_SHA", 
      "SSL_DH_DSS_WITH_3DES_EDE_CBC_SHA", 

      // RSA key transport sucks, but they are needed as a fallback. 
      // For example, microsoft.com fails under all versions of TLS 
      // if they are not included. If only TLS 1.0 is available at 
      // the client, then google.com will fail too. TLS v1.3 is 
      // trying to deprecate them, so it will be interesteng to see 
      // what happens. 
      "TLS_RSA_WITH_AES_256_CBC_SHA256", 
      "TLS_RSA_WITH_AES_256_CBC_SHA", 
      "TLS_RSA_WITH_AES_128_CBC_SHA256", 
      "TLS_RSA_WITH_AES_128_CBC_SHA" 
     }; 

     String[] availableCiphers = null; 

     try 
     { 
      SSLSocketFactory factory = m_ctx.getSocketFactory(); 
      availableCiphers = factory.getSupportedCipherSuites(); 
      Arrays.sort(availableCiphers); 
     } 
     catch(Exception e) 
     { 
      return new String[] { 
       "TLS_DHE_DSS_WITH_AES_128_CBC_SHA", 
       "TLS_DHE_DSS_WITH_AES_256_CBC_SHA", 
       "TLS_DHE_RSA_WITH_AES_128_CBC_SHA", 
       "TLS_DHE_RSA_WITH_AES_256_CBC_SHA", 
       "TLS_RSA_WITH_AES_256_CBC_SHA256", 
       "TLS_RSA_WITH_AES_256_CBC_SHA", 
       "TLS_RSA_WITH_AES_128_CBC_SHA256", 
       "TLS_RSA_WITH_AES_128_CBC_SHA", 
       "TLS_EMPTY_RENEGOTIATION_INFO_SCSV" 
      }; 
     } 

     List<String> aa = new ArrayList<String>(); 
     for(int i = 0; i < preferredCiphers.length; i++) 
     { 
      int idx = Arrays.binarySearch(availableCiphers, preferredCiphers[i]); 
      if(idx >= 0) 
       aa.add(preferredCiphers[i]); 
     } 

     aa.add("TLS_EMPTY_RENEGOTIATION_INFO_SCSV"); 

     return aa.toArray(new String[0]); 
    } 

    private SSLContext m_ctx; 

    private String[] m_ciphers; 
    private String[] m_protocols; 
} 
+0

Gracias por compartir el código . Tengo dos problemas Primero, lo que no entiendo es por qué el código contiene 2 funciones 'createSocket' cada una con diferentes argumentos. Tengo un error porque eof esto. Si cambié el nombre de uno, no sé si la llamada en código es en realidad para cuál de ellos. En segundo lugar, aparece un error en 'List aa = new ArrayList ();' diciendo 'el tipo List no es genérico; no se puede parametarizar con argumentos . – user2192774

+0

Además, ¿este código utiliza el proveedor Bouncy Castle? Debido a que las bibliotecas Java Crypto no contienen algoritmos tales como: 'CHACHA20', no veo dónde debería llamar al proveedor de Bouncy Castle en mi código. Otro problema, veo en los códigos de cifrado tales como: "TLS_ECDHE_ECDSA_WITH_CHACHA20_SHA", y "TLS_ECDHE_RSA_WITH_CHACHA20_SHA", ¿es este SHA256? porque lo que realmente necesito es CHACHA256. – user2192774

+0

@ user2192774 - * "¿por qué el código contiene 2 funciones createSocket cada una con diferentes argumentos?" * - en realidad hay 4 o 5 de ellos. Debido a que la clase es un reemplazo para 'SSLSocketFactory' de Java, tenía que proporcionar todos los métodos que tiene el original. – jww

Cuestiones relacionadas