2013-08-14 40 views
5

Piszemy aplikację, która musi komunikować się z kilkoma serwerami za pomocą protokołu HTTPS. Musi komunikować się z AWS (przy użyciu bibliotek AWS), a także z niektórymi z naszych wewnętrznych usług korzystających z TLS 1.2.HttpClient obsługujący wiele protokołów TLS

Zacząłem poprzez zmianę mojego HttpClient używać TLS 1.2 SSLContext:

public static SchemeRegistry buildSchemeRegistry() throws Exception { 
    final SSLContext sslContext = SSLContext.getInstance("TLSv1.2"); 
    sslContext.init(createKeyManager(), createTrustManager(), new SecureRandom()); 
    final SchemeRegistry schemeRegistry = new SchemeRegistry(); 
    schemeRegistry.register(new Scheme("https", 443, new SSLSocketFactory(sslContext))); 
    return schemeRegistry; 
} 

i wstrzykiwanie tej SchemeRegistry do obiektu DefaultHttpClient (przez sprężynę), ale robi, że pojawiają się błędy z AWS i tak sądzę (mogę się mylić), że AWS nie obsługuje TLS 1.2 (nie ten komunikat jeśli po prostu użyć zwykłej DefaultHttpClient):

AmazonServiceException: Status Code: 403, AWS Service: AmazonSimpleDB, AWS Request ID: 5d91d65f-7158-91b6-431d-56e1c76a844c, AWS Error Code: InvalidClientTokenId, AWS Error Message: The AWS Access Key Id you provided does not exist in our records. 

Jeśli staram się mieć dwa HttpClients zdefiniowane wiosną, jeden który używa TLS 1.2 i taki, który jest domyślny, dostaję foll z powodu błędów, które zakładam, oznacza to, że wiosna nie lubi instancji i autowiring httpclient dwa obiekty:

SEVERE: Servlet /my-refsvc threw load() exception 
java.lang.NullPointerException 
at com.company.project.refsvc.base.HttpsClientFactory.<clinit>(BentoHttpsClientFactory.java:25) 
... 
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1031) 
at 
... 
org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:223) 

Nie używałem dużo HTTPS w java więc można mili ludzie dać mi jakieś rady proszę? 1) W jaki sposób uzyskać Spring, aby umożliwić dwa obiekty HttpClient i jeden do połączenia z materiałami fasoli AWS, a drugi do połączenia z innymi komponentami bean w celu uzyskania dostępu do usług TLS1.2 2) Czy możliwa jest zmiana jeden obiekt HttpClient, aby móc wypróbować TLS1.2 (przez SSLContext, SchemeRegistry lub coś podobnego), a jeśli to się nie powiedzie, spróbuj TLS1.1 lub 1.0? 3) Jeśli oba są możliwe, jaki byłby "lepszy" sposób na zrobienie tego?

+0

Czy masz ten sam błąd przy użyciu 'SSLContext.getInstance ("TLSv1.1")' lub ' SSLContext.getInstance ("TLS") '? – Bruno

+0

Tak, pojawia się ten sam błąd. Zastanawiam się, czy jest to mój certyfikat po stronie klienta, który zepsuje to zamiast wersji TLS. – agentgonzo

+0

Spróbuj użyć domyślnego 'SSLContext' na wszelki wypadek (' SSLContext sslContext = SSLContext.getDefault() ', już zainicjalizowane). W przeciwnym razie spróbuj mniej dostosowań: 'sslContext.init (createKeyManager(), null, null)' powinien użyć wartości domyślnej dla TM i SecureRandom. Dla keymanagera nie ma wartości domyślnej, więc może być coś nie tak w twoim kodzie keymanagera (przydatne tylko wtedy, gdy serwer żąda certyfikatu klienta). – Bruno

Odpowiedz

3

TLS ma wbudowany mechanizm do negocjacji, która wersja protokołu ma być używana. Od RFC 5246 (Appendix E):

TLS wersjach 1.0, 1.1 oraz 1.2 i SSL 3.0 są bardzo podobne, a kompatybilnymi używać funkcji wiadomości ClientHello; w związku z tym wspieranie wszystkich z nich jest stosunkowo łatwe. Podobnie, serwery mogą z łatwością obsługiwać klientów próbujących korzystać z przyszłych wersji TLS, o ile format ClientHello pozostaje zgodny, a klient obsługuje najwyższą wersję protokołu dostępną na serwerze.

TLS 1.2 Klient, który chce negocjować z takich starszych serwerów wyśle ​​normalne TLS 1.2 ClientHello zawierający {3, 3} (TLS 1.2) w ClientHello.client_version. Jeśli serwer nie obsługuje tej wersji, odpowiada ona na ServerHello zawierającą starszy numer wersji . Jeśli klient zgodzi się korzystać z tej wersji, , negocjacja będzie przebiegać odpowiednio dla wynegocjowanego protokołu .

Ponadto zmienia numer wersji w SSLContext.getInstance(...) tylko zmiany, które protokoły są włączone domyślnie. Ustawianie aktualnych wersji protokołów odbywa się za pomocą SSLSocket.setEnabledProtocols(...) (patrz this question). Nie jestem pewien co do reszty używanych bibliotek, ale możliwe jest, że ustawia gdzieś włączone protokoły.

Istnieje kilka możliwości:

  • Co robisz w swoim createKeyManager() różni się od standardowego zachowania.Jeśli usługa korzysta z uwierzytelniania za pomocą certyfikatu klienta, zła konfiguracja z pewnością doprowadziłaby do błędu 403.

  • (Mniej prawdopodobne, myślę, ale trudno powiedzieć, nie widząc swoich createKeyManager() i createTrustManager()). Być może serwer, którego używasz, nie jest kompatybilny z TLS 1.2 i mechanizmem negocjacji wersji. Jest to komentarz w sun.security.ssl.SSLContextImpl:

    protokołów SSL/TLS określić kompatybilność w przód i wersję roll-back zabezpieczenia ataku, jednak liczba SSL/TLS serwerów sprzedawców nie realizować te aspekty prawidłowo, a niektóre bieżące Serwery SSL/TLS mogą odmówić rozmowy z klientem TLS 1.1 lub nowszym.

+0

Używamy uwierzytelniania za pomocą certyfikatu klienta, ale nie wiem, czy próba uwierzytelnienia na serwerach AWS za pomocą certyfikatu klienta, gdy się ich nie spodziewają, spowoduje błędy. AWS używa podpisu HMAC do uwierzytelniania, ale o wiele więcej nie wiem. createKeyManager i createTrustManager po prostu wczytaj plik .jks i zwróć z niego obiekty (nie można zakodować kodu w tym komentarzu) – agentgonzo

+0

@agentgonzo, możesz edytować swoje pytanie, jeśli chcesz opublikować więcej kodu. Czy aplikacja (domyślnie) próbuje użyć innych ustawień dla magazynu kluczy (właściwości javax.net.ssl. *)? Co się stanie, jeśli uzyskasz inne konteksty (TLS i TLSv1.1)? – Bruno