【发布时间】:2016-06-18 03:51:52
【问题描述】:
这是我的第一篇文章,我将尽力做到尽可能清晰(对不起我的英语)。
这是我的麻烦,我正在使用 retrofit:1.9.0 和 okhttp:2.7.5 来执行 API 调用。一切都很好,直到我的服务器提供商禁用 SLLv2 和 SSLv3 导致安全问题(3 月 1 日发现淹没失败)。
现在我检查了有关我的提供商的信息,他只允许来自https://www.ssllabs.com/ 的带有密码的 TLSv1 (TLS 1.0 TLS_RSA_WITH_3DES_EDE_CBC_SHA No FS)。
好的,这就是我所做的所有测试和结果:
[已解决更新问题]
在我的第二个答案中找到解决此问题的方法。
更新 似乎问题来自谷歌API版本。当我在 API 18 上进行测试时,一切正常。当它在大于或等于 5.0.0 的 Android 上失败。
第一次测试
会议。回顾:
- compileSdkVersion 23
- buildToolsVersion '23.0.2'
- minSdkVersion 18
- targetSdkVersion 21
- 改造: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 错误)
java.net.UnknownServiceException:无法找到可接受的协议。 isFallback=false, 模式=[ConnectionSpec(cipherSuites=[TLS_RSA_WITH_3DES_EDE_CBC_SHA], tlsVersions=[TLS_1_0], supportsTlsExtensions=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 错误)
javax.net.ssl.SSLProtocolException: SSL 握手中止: ssl=0x7f87885280: SSL 库失败,通常是协议错误 错误:14077410:SSL 例程:SSL23_GET_SERVER_HELLO:sslv3 警报握手失败(外部/openssl/ssl/s23_clnt.c:770 0x7f87c2fdf0:0x00000000)
如果有人可以帮助我,那将非常酷。我所有的应用程序都关闭了,我从昨天早上开始就在与这个问题作斗争,以恢复我的服务。我正在一根一根地脱毛……
提前致谢。
【问题讨论】:
-
这个解决方案解决了我的问题:stackoverflow.com/a/45853669/3448003
-
我找到了解决方案并回答了here。
标签: java android ssl https retrofit