Это мой первый пост, и я постараюсь сделать все возможное, чтобы быть как можно более ясным (извините за мой английский).
Вот моя проблема, я использую retrofit: 1.9.0 и okhttp: 2.7.5 для вызова API. Все было в порядке, пока мой серверный провайдер не отключил SLLv2 и SSLv3 из-за проблемы с безопасностью (Drown fail обнаружен в начале марта).
Теперь я проверяю информацию о моем провайдере, и он разрешает только TLSv1 с cypher (TLS 1.0 TLS_RSA_WITH_3DES_EDE_CBC_SHA Нет FS) из https://www.ssllabs.com/.
Хорошо, так что это все тесты, которые я сделал, и результаты:
[РЕШЕНИЕ ПРОБЛЕМ ОБНОВЛЕНИЯ]
Найдите способ решить эту проблему в моем втором ответе.
UPDATE Похоже, что проблемы возникают из версии API Google. Когда я тестирую API 18, все работает нормально. Когда он на Android больше или равен 5.0.0, он терпит неудачу.
Первый тест
Conf. резюме:
- compileSdkVersion 23
- buildToolsVersion '23.0.2 '
- minSdkVersion 18
- targetSdkVersion 21
- retrofit: 1.9.0
- okhttp: 2.7.5
- версия Android > 5.0.0 (но она одинакова на каждом устройстве...)
Клиент для отдыха (LoginRestClient):
public class LoginRestClient
{
private static final String BASE_URL = "";
private LoginApiService apiService;
public LoginRestClient()
{
Gson gson = new GsonBuilder()
.setDateFormat("yyyy'-'MM'-'dd'T'HH':'mm':'ss'.'SSS'Z'")
.create();
RestAdapter restAdapter = new RestAdapter.Builder()
.setLogLevel(RestAdapter.LogLevel.FULL)
.setEndpoint(ApiIntentService.getHostAddress())
.setConverter(new GsonConverter(gson))
.setClient(new OkClient(ApiIntentService.getConnectionHttpClient()))
.build();
apiService = restAdapter.create(LoginApiService.class);
}
public LoginApiService getApiService() {
return apiService;
}
}
Функция создания клиента OkHttpClient getConnectionHttpClient()
public static OkHttpClient getConnectionHttpClient()
{
OkHttpClient okHttpClient = new OkHttpClient();
okHttpClient.setReadTimeout(60, TimeUnit.SECONDS);
okHttpClient.setConnectTimeout(60, TimeUnit.SECONDS);
ConnectionSpec specs = new ConnectionSpec.Builder(ConnectionSpec.COMPATIBLE_TLS)
.tlsVersions(TlsVersion.TLS_1_0)
.cipherSuites(CipherSuite.TLS_RSA_WITH_3DES_EDE_CBC_SHA)
.build();
okHttpClient.setConnectionSpecs(Collections.singletonList(specs));
return okHttpClient;
}
Результат публичного недействительности (RetrofitError error) из пользовательского CallBack
java.net.UnknownServiceException: невозможно найти приемлемые протоколы. isFallback = false, modes = [ConnectionSpec (cipherSuites = [TLS_RSA_WITH_3DES_EDE_CBC_SHA], tlsVersions = [TLS_1_0], поддерживаетTlsExtensions = true)], поддерживаемые протоколы = [SSLv3, TLSv1, TLSv1.1, TLSv1.2]
Второй тест
Я создал специальный SSLSocketFactory для отключения SSLv3 и принудительного использования TLS:
/**
* @author fkrauthan
*/
public class TLSSocketFactory extends SSLSocketFactory {
private SSLSocketFactory internalSSLSocketFactory;
public TLSSocketFactory() throws KeyManagementException, NoSuchAlgorithmException {
SSLContext context = SSLContext.getInstance("TLS");
context.init(null, null, null);
internalSSLSocketFactory = context.getSocketFactory();
}
@Override
public String[] getDefaultCipherSuites() {
return internalSSLSocketFactory.getDefaultCipherSuites();
}
@Override
public String[] getSupportedCipherSuites() {
return internalSSLSocketFactory.getSupportedCipherSuites();
}
@Override
public Socket createSocket(Socket s, String host, int port, boolean autoClose) throws IOException {
return enableTLSOnSocket(internalSSLSocketFactory.createSocket(s, host, port, autoClose));
}
@Override
public Socket createSocket(String host, int port) throws IOException, UnknownHostException {
return enableTLSOnSocket(internalSSLSocketFactory.createSocket(host, port));
}
@Override
public Socket createSocket(String host, int port, InetAddress localHost, int localPort) throws IOException, UnknownHostException {
return enableTLSOnSocket(internalSSLSocketFactory.createSocket(host, port, localHost, localPort));
}
@Override
public Socket createSocket(InetAddress host, int port) throws IOException {
return enableTLSOnSocket(internalSSLSocketFactory.createSocket(host, port));
}
@Override
public Socket createSocket(InetAddress address, int port, InetAddress localAddress, int localPort) throws IOException {
return enableTLSOnSocket(internalSSLSocketFactory.createSocket(address, port, localAddress, localPort));
}
private Socket enableTLSOnSocket(Socket socket) {
if(socket != null && (socket instanceof SSLSocket)) {
((SSLSocket)socket).setEnabledProtocols(new String[] {"TLSv1"});
}
return socket;
}
}
Я использую его следующим образом:
public static OkHttpClient getConnectionHttpClient()
{
OkHttpClient okHttpClient = new OkHttpClient();
okHttpClient.setReadTimeout(60, TimeUnit.SECONDS);
okHttpClient.setConnectTimeout(60, TimeUnit.SECONDS);
try {
TLSSocketFactory tlsSocketFactory = new TLSSocketFactory();
HttpsURLConnection.setDefaultSSLSocketFactory(tlsSocketFactory);
okHttpClient.setSslSocketFactory(tlsSocketFactory);
} catch (KeyManagementException e) {
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
return okHttpClient;
}
Результат публичного недействительности (RetrofitError error) из пользовательского CallBack
javax.net.ssl.SSLProtocolException: SSL-рукопожатие отменено: ssl = 0x7f87885280: ошибка в библиотеке SSL, как правило, ошибка протокола Ошибка: 14077410: Процедуры SSL: SSL23_GET_SERVER_HELLO: сбой сброса предупреждения sslv3 (внешний/openssl/ssl/s23_clnt.c: 770 0x7f87c2fdf0: 0x00000000)
Если кто-нибудь может мне помочь Это будет очень круто. Все мои приложения отключены, и я борюсь с этой проблемой со вчерашнего утра, чтобы восстановить свои услуги. Я удаляю свои волосы один за другим...
Спасибо заранее.