¿Qué suites de cifrado habilitar para SSL Socket?

Estoy usando SSLSocket de Java para asegurar las comunicaciones entre un cliente y un progtwig de servidor. El progtwig de servidor también sirve solicitudes HTTPS desde navegadores web.

De acuerdo con ” Beginning Cryptography with Java “, página 371, siempre debe llamar a setEnabledCipherSuites en su SSLSocket / SSLServerSocket para asegurarse de que el conjunto de cifrado que termina siendo negociado sea lo suficientemente fuerte para sus propósitos.

Dicho esto, una llamada al método getDefaultCipherSuites mi SSLSocketFactory produce unas 180 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 sockets?

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

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

EDITAR: Modificado para usar el documento de 2009.

Una recomendación de NIST de 2009 enumera lo siguiente, incluido TLS_RSA_WITH_AES_256_CBC_SHA (que usted mencionó):

TLS_RSA_WITH_NULL_SHA (no use esto a menos que esté seguro de que no necesita 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 

A continuación se muestra la clase de Java que utilizo para aplicar suites y protocolos de cifrado. Antes de SSLSocketFactoryEx , estaba modificando las propiedades en 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 suites de cifrado más fuertes (como ECDHE y DHE ), y omite las suites 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 no está 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 publicita todos los cifrados disponibles (similar a la lista de Flaschen), entonces su lista será más de 80. Eso requiere 160 bytes en ClientHello , y puede hacer que algunos dispositivos fallen porque tienen un pequeño buffer de tamaño fijo para procesar ClientHello . Los dispositivos rotos incluyen F5 y Ironport.

En la práctica, la lista en el siguiente código está emparejada con 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 a microsoft.com o google.com con una política de JCE ilimitada:

  • 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_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 reciba una advertencia de criptografía obsoleta desde el navegador 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 asegura que se usan 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 introducirá SSLv3 (incluso en Java 8), por lo que se deben seguir pasos 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 .

Puedes usarlo así:

 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 aa = new ArrayList(); 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 aa = new ArrayList(); 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; }