java Android 4.4.2 SSL 握手中止
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/34493334/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Android 4.4.2 SSL handshake aborted
提问by Lee Tickett
Code works on my Genymotion Android 4.4.4 emulator but not on the device i'm using (4.4.2).
代码适用于我的 Genymotion Android 4.4.4 模拟器,但不适用于我正在使用的设备 (4.4.2)。
I've tried lots of "trust all certificate" workarounds but to no avail (I don't think this is the issue anyway, as the certificate is AOK).
我已经尝试了很多“信任所有证书”的解决方法,但都无济于事(无论如何,我认为这不是问题,因为证书是 AOK)。
I think I have identified the cipher (using a wireshark trace from my desktop); TLS 0x00 0x1E which appears to be somewhat rare?
我想我已经确定了密码(使用我桌面上的 wireshark 跟踪);TLS 0x00 0x1E 这似乎有点少见?
Any idea how to fix?
知道如何解决吗?
Here's my code
这是我的代码
StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
StrictMode.setThreadPolicy(policy);
CloseableHttpClient client = HttpClientBuilder.create().setSSLSocketFactory(sslsf).build();
String baseURL = "https://mysite.co.uk/api/";
HttpGetHC4 request = new HttpGetHC4(baseURL + "/authenticate?user=abcd&password=1234");
CloseableHttpResponse response = client.execute(request);
And error;
和错误;
javax.net.ssl.SSLHandshakeException: javax.net.ssl.SSLProtocolException: SSL handshake aborted: ssl=0x6abff398: Failure in SSL library, usually a protocol error
error:14077410:SSL routines:SSL23_GET_SERVER_HELLO:sslv3 alert handshake failure (external/openssl/ssl/s23_clnt.c:744 0x684dfce0:0x00000000)
at com.android.org.conscrypt.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:449)
at org.apache.http.conn.ssl.SSLConnectionSocketFactory.createLayeredSocket(SSLConnectionSocketFactory.java:340)
at org.apache.http.conn.ssl.SSLConnectionSocketFactory.connectSocket(SSLConnectionSocketFactory.java:281)
at org.apache.http.impl.conn.HttpClientConnectionOperator.connect(HttpClientConnectionOperator.java:124)
at org.apache.http.impl.conn.BasicHttpClientConnectionManager.connect(BasicHttpClientConnectionManager.java:322)
at org.apache.http.impl.execchain.MainClientExec.establishRoute(MainClientExec.java:373)
at org.apache.http.impl.execchain.MainClientExec.execute(MainClientExec.java:225)
at org.apache.http.impl.execchain.ProtocolExec.execute(ProtocolExec.java:195)
at org.apache.http.impl.execchain.RetryExec.execute(RetryExec.java:86)
at org.apache.http.impl.execchain.RedirectExec.execute(RedirectExec.java:108)
at org.apache.http.impl.client.InternalHttpClient.doExecute(InternalHttpClient.java:178)
at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:82)
at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:106)
at com.example.lee.printticket.Main$OrderAsyncTask.onPostExecute(Main.java:239)
at com.example.lee.printticket.Main$OrderAsyncTask.onPostExecute(Main.java:189)
at android.os.AsyncTask.finish(AsyncTask.java:632)
at android.os.AsyncTask.access0(AsyncTask.java:177)
at android.os.AsyncTask$InternalHandler.handleMessage(AsyncTask.java:645)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:136)
at android.app.ActivityThread.main(ActivityThread.java:5017)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:515)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:785)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:601)
at dalvik.system.NativeStart.main(Native Method)
Caused by: javax.net.ssl.SSLProtocolException: SSL handshake aborted: ssl=0x6abff398: Failure in SSL library, usually a protocol error
error:14077410:SSL routines:SSL23_GET_SERVER_HELLO:sslv3 alert handshake failure (external/openssl/ssl/s23_clnt.c:744 0x684dfce0:0x00000000)
at com.android.org.conscrypt.NativeCrypto.SSL_do_handshake(Native Method)
at com.android.org.conscrypt.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:406)
... 25 more
EDIT
编辑
Trying using a different technique/library;
尝试使用不同的技术/库;
RequestQueue queue = Volley.newRequestQueue(this);
String url ="https://mysite.co.uk/api/authenticate?user=abcd&password=1234";
// Request a string response from the provided URL.
StringRequest stringRequest = new StringRequest(Request.Method.GET, url,
new Response.Listener<String>() {
@Override
public void onResponse(String response) {
// Display the first 500 characters of the response string.
Log.d("response: ", response);
}
}, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
Log.d("response: ", error.toString());
}
});
// Add the request to the RequestQueue.
queue.add(stringRequest);
Returns;
退货;
D/response:: com.android.volley.NoConnectionError: javax.net.ssl.SSLHandshakeException: javax.net.ssl.SSLProtocolException: SSL handshake aborted: ssl=0x6ad51be0: Failure in SSL library, usually a protocol error
D/response:: error:140740B5:SSL routines:SSL23_CLIENT_HELLO:no ciphers available (external/openssl/ssl/s23_clnt.c:486 0x684dfce0:0x00000000)
Or with the NoSSLv3SocketFactory hack from Javax.net.ssl.SSLHandshakeException: javax.net.ssl.SSLProtocolException: SSL handshake aborted: Failure in SSL library, usually a protocol error;
或者使用来自 Javax.net.ssl.SSLHandshakeException : javax.net.ssl.SSLProtocolException: SSL handshake aborted: Failure in SSL library, 通常是协议错误的 NoSSLv3SocketFactory hack ;
HttpStack stack = new HurlStack(null, new NoSSLv3SocketFactory());
RequestQueue queue = Volley.newRequestQueue(this, stack);
Returns;
退货;
D/response:: com.android.volley.NoConnectionError: javax.net.ssl.SSLHandshakeException: javax.net.ssl.SSLProtocolException: SSL handshake aborted: ssl=0x6ae51d30: Failure in SSL library, usually a protocol error
D/response:: error:14077410:SSL routines:SSL23_GET_SERVER_HELLO:sslv3 alert handshake failure (external/openssl/ssl/s23_clnt.c:744 0x684dfce0:0x00000000)
回答by user9453341
Android uses different protocols for network operations.
Android 使用不同的协议进行网络操作。
Default configuration for different Android versions.
不同安卓版本的默认配置。
I found solution for OkHttpClient.
我找到了 OkHttpClient 的解决方案。
Protocol Supported (API Levels) Enabled by default (API Levels)
SSLv3 1–25 1–22
TLSv1 1+ 1+
TLSv1.1 16+ 20+
TLSv1.2 16+ 20+
So we have to change Protocol for connection in Android VERSION >= 16 & VERSION < 22.
所以我们必须在 Android VERSION >= 16 & VERSION < 22 中更改连接协议。
Create java file Tls12SocketFactory.java
创建 java 文件Tls12SocketFactory.java
/**
* Enables TLS v1.2 when creating SSLSockets.
* <p/>
* For some reason, android supports TLS v1.2 from API 16, but enables it by
* default only from API 20.
* @link https://developer.android.com/reference/javax/net/ssl/SSLSocket.html
* @see SSLSocketFactory
*/
public class Tls12SocketFactory extends SSLSocketFactory {
private static final String[] TLS_V12_ONLY = {"TLSv1.2"};
final SSLSocketFactory delegate;
public Tls12SocketFactory(SSLSocketFactory base) {
this.delegate = base;
}
@Override
public String[] getDefaultCipherSuites() {
return delegate.getDefaultCipherSuites();
}
@Override
public String[] getSupportedCipherSuites() {
return delegate.getSupportedCipherSuites();
}
@Override
public Socket createSocket(Socket s, String host, int port, boolean autoClose) throws IOException {
return patch(delegate.createSocket(s, host, port, autoClose));
}
@Override
public Socket createSocket(String host, int port) throws IOException, UnknownHostException {
return patch(delegate.createSocket(host, port));
}
@Override
public Socket createSocket(String host, int port, InetAddress localHost, int localPort) throws IOException, UnknownHostException {
return patch(delegate.createSocket(host, port, localHost, localPort));
}
@Override
public Socket createSocket(InetAddress host, int port) throws IOException {
return patch(delegate.createSocket(host, port));
}
@Override
public Socket createSocket(InetAddress address, int port, InetAddress localAddress, int localPort) throws IOException {
return patch(delegate.createSocket(address, port, localAddress, localPort));
}
private Socket patch(Socket s) {
if (s instanceof SSLSocket) {
((SSLSocket) s).setEnabledProtocols(TLS_V12_ONLY);
}
return s;
}
}
Put this method some where in your code.
将此方法放在代码中的某个位置。
public static OkHttpClient.Builder enableTls12OnPreLollipop(OkHttpClient.Builder client) {
if (Build.VERSION.SDK_INT >= 16 && Build.VERSION.SDK_INT < 22) {
try {
SSLContext sc = SSLContext.getInstance("TLSv1.2");
sc.init(null, null, null);
client.sslSocketFactory(new Tls12SocketFactory(sc.getSocketFactory()));
ConnectionSpec cs = new ConnectionSpec.Builder(ConnectionSpec.MODERN_TLS)
.tlsVersions(TlsVersion.TLS_1_2).build();
List<ConnectionSpec> specs = new ArrayList<>();
specs.add(cs);
specs.add(ConnectionSpec.COMPATIBLE_TLS);
specs.add(ConnectionSpec.CLEARTEXT);
client.connectionSpecs(specs);
} catch (Exception exc) {
Log.e("OkHttpTLSCompat", "Error while setting TLS 1.2", exc);
}
}
return client;
}
public OkHttpClient getNewHttpClient() {
OkHttpClient.Builder client = new OkHttpClient.Builder().followRedirects(true).followSslRedirects(true)
.retryOnConnectionFailure(true).cache(null).connectTimeout(5, TimeUnit.SECONDS)
.writeTimeout(5, TimeUnit.SECONDS).readTimeout(5, TimeUnit.SECONDS);
return enableTls12OnPreLollipop(client).build();
}
Create OkHttp instance like below :
创建 OkHttp 实例如下:
private OkHttpClient getNewHttpClient() {
OkHttpClient.Builder client = new OkHttpClient.Builder()
.followRedirects(true)
.followSslRedirects(true)
.retryOnConnectionFailure(true)
.cache(null)
.connectTimeout(5, TimeUnit.SECONDS)
.writeTimeout(5, TimeUnit.SECONDS)
.readTimeout(5, TimeUnit.SECONDS);
return enableTls12OnPreLollipop(client).build();
}
Use client object like this:
像这样使用客户端对象:
OkHttpClient client = getNewHttpClient();
Request.Builder requestBuilder = new Request.Builder();
URL url = new URL("YOUR_URL_LINK");
Request request = requestBuilder.url(url).build();
Call call = client.newCall(request);
Response response = call.execute();
回答by GuilhE
Try this:
试试这个:
public class ClientSSLSocketFactory {
public static SSLSocketFactory getSocketFactory(Context context) {
try {
X509TrustManager tm = new X509TrustManager() {
public void checkClientTrusted(X509Certificate[] xcs, String string) throws CertificateException {
}
public void checkServerTrusted(X509Certificate[] xcs, String string) throws CertificateException {
}
public X509Certificate[] getAcceptedIssuers() {
return new X509Certificate[0];
}
};
SSLContext ctx = SSLContext.getInstance("TLS");
ctx.init(null, new TrustManager[]{tm}, new SecureRandom());
SSLSocketFactory ssf = SSLCertificateSocketFactory.getDefault(10000, new SSLSessionCache(context));
return ssf;
} catch (Exception ex) {
Log.e("ssl", "Error during the getSocketFactory");
ex.printStackTrace();
return null;
}
}
}
And when creating the queue:
在创建队列时:
sRequestQueue = Volley.newRequestQueue(context, new HurlStack(null, ClientSSLSocketFactory.getSocketFactory()));
Hope it helps.
希望能帮助到你。
回答by Sean F
I believe the problem is SSL v3 based on strings like this suggesting that it is attempting to use SSL v3: SSL23_GET_SERVER_HELLO:sslv3
我相信问题是基于这样的字符串的 SSL v3,这表明它正在尝试使用 SSL v3: SSL23_GET_SERVER_HELLO:sslv3
SSL v3 is considered insecure and thus disabled on most modern software (even in places where you would otherwise expect it to work, many companies have simply yanked it out). I also see from the stack trace that the code uses apache http client: org.apache.http.impl.client
SSL v3 被认为是不安全的,因此在大多数现代软件上都被禁用(即使在您期望它可以正常工作的地方,许多公司也干脆将其删除了)。我还从堆栈跟踪中看到代码使用了 apache http 客户端:org.apache.http.impl.client
So you have to somehow prevent that apache http client from using ssl v3. Apache http client exists separately from the standard Java SSL/TLS libraries.
所以你必须以某种方式阻止 apache http 客户端使用 ssl v3。Apache http 客户端与标准 Java SSL/TLS 库分开存在。
There is another stackoverflow question that received no answers: How do disable SSLv3 in Apache HttpClient
还有另一个没有得到答案的 stackoverflow 问题: How do disable SSLv3 in Apache HttpClient
This link looks most promising: https://discretemkt.wordpress.com/2014/11/16/commons-httpclient-can-disable-sslv3/
这个链接看起来最有前途:https: //discretemkt.wordpress.com/2014/11/16/commons-httpclient-can-disable-sslv3/
In there, the key line is
在那里,关键是
Protocol.registerProtocol(scheme, customHttps);
That call appears to allow you to bypass the existing ssl factory. If you run that code first it may work, assuming the apache http client versions are compatible.
该调用似乎允许您绕过现有的 ssl 工厂。如果您首先运行该代码它可能会工作,假设 apache http 客户端版本是兼容的。
Also note that TLS 1.0 is also considered insecure these days. TLS 1.2 and 1.3 and the standard now.
另请注意,如今 TLS 1.0 也被认为是不安全的。TLS 1.2 和 1.3 以及现在的标准。