2009-06-24 8 views
19

Używam protokołu SSLSocket języka Java do zabezpieczenia komunikacji między klientem a programem serwera. Program serwera obsługuje również żądania HTTPS z przeglądarek internetowych.Jakie pakiety algorytmów szyfrowania mają być włączone dla gniazda SSL?

Według „Beginning Cryptography with Java”, strona 371, należy zawsze zadzwonić setEnabledCipherSuites na swój SSLSocket/SSLServerSocket aby upewnić się, że szyfr apartament, który kończy się w fazie negocjacji jest wystarczająco silny dla swoich celów.

Mimo to połączenie z moją metodą 'getDefaultCipherSuites daje niektóre opcje . Opcje te obejmują od TLS_RSA_WITH_AES_256_CBC_SHA (co moim zdaniem jest dość bezpieczne) do SSL_RSA_WITH_RC4_128_MD5 (nie jestem pewien, czy jest to bezpieczne, biorąc pod uwagę aktualny stan MD5) do SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA (nie jestem do końca pewien, co to robi).

Jaka jest rozsądna lista zestawów szyfrów do ograniczenia gniazd?

Należy pamiętać, że klient i serwer mają dostęp do dostawcy usług Bouncy Castle i mogą mieć lub nie mieć nieograniczoną liczbę plików zasad kryptograficznych.

+0

'TLS_RSA_WITH_AES_256_CBC_SHA' ... - należy prawdopodobnie uniknąć kluczowych systemów transportowych RSA (lub umieścić je w dolnej części reklamowanej listy). Zamiast tego poproś o efemeryczne wymiany kluczy, takie jak 'DHE', w celu zachowania poufności. W rzeczywistości, TLS 1.3 omawia ich usunięcie, ponieważ nie mają one właściwości. – jww

+0

'SSL_RSA_WITH_RC4_128_MD5' ... -' RC4' jest teraz problemem dziecka. Zobacz [Na temat bezpieczeństwa RC4 w TLS i WPA] (http://www.isg.rhul.ac.uk/tls/). Atakujący prawdopodobnie * nie może * sfałszować sygnatury 'HMAC-MD5' w oknie czasowym 2MSL sieci. Jednak atakujący może statystycznie skorelować bity w strumieniu szyfrów. (I MD5 * jest * martwy dla długotrwałego użytkowania, jak certyfikaty i podpisy cyfrowe). – jww

+0

'SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA' ... - nagraj go. Unikaj go jak ognia. – jww

Odpowiedz

7

Nie używaj niczego z eksportem. To kalekie z powodu restrykcji eksportowych dotyczących silnej kryptografii.

EDYCJA: Zmieniono, aby użyć dokumentu z 2009 roku.

A 2009 NIST recommendation wymienia następujące, incluing TLS_RSA_WITH_AES_256_CBC_SHA (które można wymienić):

TLS_RSA_WITH_NULL_SHA (nie używać tej opcji, chyba że jesteś pewien, że nie potrzeba żadnego prywatności/poufności).

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

Jestem nieco zdezorientowany TLS_RSA_WITH_NULL_SHA - czy to nie określa szyfrowania? W tym kontekście oznacza to * nie * lub * dowolne * szyfrowanie? – Zarkonnen

+2

Zarkonnen, myślę, że masz rację, że TLS_RSA_WITH_NULL_SHA oznacza brak szyfrowania. str. 34 projektu I linked mówi, że szyfrowanie NULL jest dla "przypadków, w których ochrona integralności jest wymagana, ale nie szyfrowanie". –

+1

Wątpię, czy potrzebuje on kluczy szyfrujących (PSK), takich jak 'TLS_PSK_WITH_3DES_EDE_CBC_SHA'. 'TLS_RSA_WITH_AES_256_CBC_SHA' używa transportu kluczy RSA. Powinien prawdopodobnie używać 'DHE' lub' ECDHE' do zachowania poufności. – jww

15

Poniżej znajduje się klasa Java, której używam do wymuszania zestawów szyfrów i protokołów. Przed SSLSocketFactoryEx modyfikowałem właściwości na SSLSocket, gdy miałem do nich dostęp. Ludzie z Java w Stack Overflow pomogli z tym, więc miło jest móc go opublikować tutaj.

SSLSocketFactoryEx preferuje silniejsze szyfrów (jak ECDHE i DHE), i pomija słabe i rannych szyfrów (jak RC4 i MD5). Musi włączyć cztery szyfry transportowe RSA do współdziałania z Google i Microsoft, gdy dostępny jest TLS 1.2 , a nie. Są to: TLS_RSA_WITH_AES_256_CBC_SHA256, TLS_RSA_WITH_AES_256_CBC_SHA i dwóch przyjaciół. Jeśli to możliwe, należy usunąć schematy transportu kluczy z kluczem TLS_RSA_*.

Lista pakietów szyfrów powinna być jak najmniejsza. Jeśli zarejestrujesz wszystkie dostępne cyfry (podobne do listy Flaschena), twoja lista będzie wynosić 80+. Zajmuje to 160 bajtów w urządzeniu ClientHello i może spowodować awarię niektórych urządzeń, ponieważ mają mały bufor o stałym rozmiarze do przetwarzania ClientHello. Zepsute urządzenia to F5 i Ironport.

W praktyce lista w poniższym kodzie jest sparowana do 10 lub 15 zestawów szyfrów, gdy preferowana lista zostanie przecięta z obsługiwanymi pakietami algorytmu Java. Na przykład, oto lista, którą otrzymuję przygotowując się do połączenia lub microsoft.com lub google.com z nieograniczonej polityki JCE w lokalu:

  • 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

Lista pomija słabe/zranione algorytmy, takie jak RC4 i MD5. Jeśli są włączone, prawdopodobnie będziesz czasem otrzymywać Obsolete cryptography warning from Browser.

Lista będzie mniejsza z domyślną zasadą JCE, ponieważ strategia usuwa AES-256 i kilka innych. Myślę, że jest to około 7 zestawów szyfrów o ograniczonej polityce.

Klasa SSLSocketFactoryEx zapewnia również protokoły TLS 1.0 i nowsze. Klienci Java przed wersją 8 Java wyłączają TLS 1.1 i 1.2. SSLContext.getInstance("TLS") będzie również przekradać się w SSLv3 (nawet w Javie 8), więc należy podjąć kroki, aby go usunąć.

Wreszcie, poniższa klasa ma świadomość TLS 1.3, więc powinna działać, gdy dostawca je udostępnia. Zestawy szyfrów *_CHACHA20_POLY1305 są preferowane, jeśli są dostępne, ponieważ są o wiele szybsze niż niektóre z obecnych pakietów i mają lepsze właściwości zabezpieczeń. Google już rozwinął to na swoich serwerach. Nie jestem pewien, kiedy Oracle je dostarczy. OpenSSL zapewni im OpenSSL 1.0.2 1.1.0.

Można go używać tak:

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

Dzięki za udostępnienie kodu . Mam dwie problemy. Po pierwsze, nie rozumiem, dlaczego kod zawiera 2 funkcje "createSocket", z których każda ma inne argumenty? Mam błąd z tego powodu. Jeśli zmieniłem nazwę jednego, nie wiem, czy wywołanie w kodzie jest w rzeczywistości, dla którego jeden z nich. Po drugie, pojawia się błąd w liście 'List aa = new ArrayList ();' mówiąc 'lista typów nie jest generyczna; nie można go parametryzować za pomocą argumentów . – user2192774

+0

Czy ten kod jest również używany przez dostawcę skoczni odrzutowych? Ponieważ biblioteki Java Crypto nie zawierają algorytmów takich jak: 'CHACHA20', nie widzę, gdzie powinienem nazwać dostawcę Skoczków Zamkowych w moim kodzie. Inną kwestią, którą widzę w szyfrach kodu, takich jak: "TLS_ECDHE_ECDSA_WITH_CHACHA20_SHA", i "TLS_ECDHE_RSA_WITH_CHACHA20_SHA", jest to SHA256? bo czego potrzebuję, to CHACHA256. – user2192774

+0

@ user2192774 - * "dlaczego kod zawiera 2 funkcje createSocket, każda z różnymi argumentami?" * - w rzeczywistości jest ich 4 lub 5. Ponieważ klasa jest zamiennikiem dla 'SSLSocketFactory 'języka Java, musiała dostarczyć wszystkie metody, jakie wykonuje oryginalna. – jww

Powiązane problemy