我正在尝试从Andorid版本4.1.1中的Android应用程序连接到URL,我收到了问题标题中指出的错误,但是当我尝试从Andorid版本4.0.4或3.1连接相同的URL时一切正常.
代码片段:
try {
.
.
.
URL url = new URL(urlStr);
Log.i(TAG,"[ URL ] " + urlStr);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
int size = conn.getContentLength();
int responsecode = conn.getResponseCode();
Log.d(TAG, "Responsecode: " + responsecode);
.
.
.
} catch (Exception e) {
e.printStackTrace();
}
private static void trustAllHosts() {
TrustManager[] trustAllCerts = new TrustManager[] { new X509TrustManager() {
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
return new java.security.cert.X509Certificate[] {};
}
public void checkClientTrusted(X509Certificate[] chain,
String authType) throws CertificateException {
}
public void checkServerTrusted(X509Certificate[] chain,
String authType) throws CertificateException {
}
} };
try {
SSLContext sc = SSLContext.getInstance("TLS");
sc.init(null, trustAllCerts, new java.security.SecureRandom());
HttpsURLConnection
.setDefaultSSLSocketFactory(sc.getSocketFactory());
} catch (Exception e) {
System.out.println("IOException : HTTPSRequest::trustAllHosts");
e.printStackTrace();
}
}
Run Code Online (Sandbox Code Playgroud)
但在这里我清楚一点是"可能证书是自签名证书,并不包括在KeyStore中.
我不明白为什么这个只在Android Verison 4.1.1操作系统中发生.谢谢.
完全堆积的痕迹
01-31 10:26:08.348: W/System.err(3158): java.io.IOException: Hostname <URL> was not verified
01-31 10:26:08.348: W/System.err(3158): at libcore.net.http.HttpConnection.verifySecureSocketHostname(HttpConnection.java:223)
01-31 10:26:08.348: W/System.err(3158): at libcore.net.http.HttpsURLConnectionImpl$HttpsEngine.connect(HttpsURLConnectionImpl.java:446)
01-31 10:26:08.348: W/System.err(3158): at libcore.net.http.HttpEngine.sendSocketRequest(HttpEngine.java:289)
01-31 10:26:08.348: W/System.err(3158): at libcore.net.http.HttpEngine.sendRequest(HttpEngine.java:239)
01-31 10:26:08.348: W/System.err(3158): at libcore.net.http.HttpURLConnectionImpl.getResponse(HttpURLConnectionImpl.java:273)
01-31 10:26:08.348: W/System.err(3158): at libcore.net.http.HttpURLConnectionImpl.getHeaderField(HttpURLConnectionImpl.java:130)
01-31 10:26:08.348: W/System.err(3158): at java.net.URLConnection.getHeaderFieldInt(URLConnection.java:544)
01-31 10:26:08.348: W/System.err(3158): at java.net.URLConnection.getContentLength(URLConnection.java:316)
01-31 10:26:08.348: W/System.err(3158): at libcore.net.http.HttpsURLConnectionImpl.getContentLength(HttpsURLConnectionImpl.java:191)
01-31 10:26:08.348: W/System.err(3158): at com.ih.util.HelpVideoServices$downloadTask.run(HelpVideoServices.java:172)
Run Code Online (Sandbox Code Playgroud)
小智 59
如果您运行的证书没有任何意义,并且您想要绕过它们,您还需要添加一个空主机名验证程序以使此代码正常工作
HttpsURLConnection.setDefaultHostnameVerifier(new NullHostNameVerifier());
SSLContext context = SSLContext.getInstance("TLS");
context.init(null, new X509TrustManager[]{new NullX509TrustManager()}, new SecureRandom());
HttpsURLConnection.setDefaultSSLSocketFactory(context.getSocketFactory());
Run Code Online (Sandbox Code Playgroud)
以及主机的代码:
import javax.net.ssl.HostnameVerifier ;
import javax.net.ssl.SSLSession;
public class NullHostNameVerifier implements HostnameVerifier {
@Override
public boolean verify(String hostname, SSLSession session) {
Log.i("RestUtilImpl", "Approving certificate for " + hostname);
return true;
}
}
Run Code Online (Sandbox Code Playgroud)
这需要运行一次,但如果要对连接对象进行更改,则可能需要再次运行它.
Mat*_*aga 19
除了@Noam的回答,这是一个完整的例子:
/**
* Disables the SSL certificate checking for new instances of {@link HttpsURLConnection} This has been created to
* aid testing on a local box, not for use on production.
*/
private static void disableSSLCertificateChecking() {
TrustManager[] trustAllCerts = new TrustManager[] {
new X509TrustManager() {
@Override
public void checkClientTrusted(java.security.cert.X509Certificate[] x509Certificates, String s) throws java.security.cert.CertificateException {
// not implemented
}
@Override
public void checkServerTrusted(java.security.cert.X509Certificate[] x509Certificates, String s) throws java.security.cert.CertificateException {
// not implemented
}
@Override
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
return null;
}
}
};
try {
HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() {
@Override
public boolean verify(String s, SSLSession sslSession) {
return true;
}
});
SSLContext sc = SSLContext.getInstance("TLS");
sc.init(null, trustAllCerts, new java.security.SecureRandom());
HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
} catch (KeyManagementException e) {
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
}
Run Code Online (Sandbox Code Playgroud)
希望能帮助到你
我在4.1.1和4.1.2中使用HTTPSUrlConnection遇到了这个问题.
经过一番探索,我发现这是因为我正在处理的Apache服务器有多个服务于https流量的虚拟主机,导致Android 中的SNI问题 - 至少在JellyBean之前(我有未经证实的报道称它在JB中工作).
就我而言,有3个虚拟主机提供https流量:
使用openssl_client探测api.*,如下所示:
openssl s_client -debug -connect api.mydomain.com:443
Run Code Online (Sandbox Code Playgroud)
...总是返回根域的证书 - 埋在输出中是这样的:
Certificate chain
0 s:/OU=Domain Control Validated/CN=mydomain.com
...
Run Code Online (Sandbox Code Playgroud)
...在openssl_client命令行中指定服务器名称:
openssl s_client -debug -servername api.mydomain.com -connect api.mydomain.com:443
Run Code Online (Sandbox Code Playgroud)
...返回了我期待看到的证书:
Certificate chain
0 s:/OU=Domain Control Validated/CN=api.mydomain.com
Run Code Online (Sandbox Code Playgroud)
我能够通过将根域虚拟主机移动到其他物理主机来解决问题.
似乎Android HostnameVerifier可以与多个子域并排作为虚拟主机,但在同一个apache 中将根域作为虚拟主机会导致问题.
我不是一个sys-admin/dev-ops,所以有可能有Apache配置选项可以解决我不知道的问题.
请注意 SSL 证书仅适用于域,不适用于 IP 地址。
如果您使用 IP,请插入以下代码
HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier()
{
@Override
public boolean verify(String hostname, SSLSession session)
{
if(hostname.equals("127.0.0.1"))
return true;
}
});
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
48860 次 |
最近记录: |