Android SSL 连接到 Tomcat(自签名证书)SSLPeerUnverifiedException

标签 android ssl https tomcat7

我目前正在尝试在一个简单的测试应用程序中实现 ssl 连接。

设置: 带有 Tomcat 7 的 Ubuntu 服务器 14.04.3 内网IP:192.168.189.42 Tomcat SSL:

https://192.168.177.42:8443/

SSL 证书创建于:Tomcat Tutorial 设备:API23 平板电脑虚拟机(Hyper-V、Visual Studio) IDE:安卓工作室

首先,我通过 AsyncTask 测试了与 Google 的 ssl 连接:

URL url = new URL("https://google.de");
URLConnection urlConnection = url.openConnection();
InputStream in = urlConnection.getInputStream();
in.close();

效果很好。

所以我用这个命令从 keystore 中提取了证书:

keytool -export -alias tomcat -file server.cer -keystore .keystore

我将该文件放入:myproject/res/raw/server.cer

在另一个 AsyncTask 中,我使用了 sample code从谷歌开发者创建连接:

        CertificateFactory cf = CertificateFactory.getInstance("X.509");
        InputStream caInput = new BufferedInputStream(context.getResources().openRawResource(R.raw.server));
        Certificate ca;

        ca = cf.generateCertificate(caInput);

        Log.d("CERT: ", "ca=" + ((X509Certificate) ca).getSubjectDN());

        caInput.close();

        String keyStoreType = KeyStore.getDefaultType();
        KeyStore keyStore = KeyStore.getInstance(keyStoreType);
        keyStore.load(null, null);
        keyStore.setCertificateEntry("ca", ca);

        String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
        TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmfAlgorithm);
        tmf.init(keyStore);

        SSLContext context = SSLContext.getInstance("TLS");
        context.init(null, tmf.getTrustManagers(), null);

        URL url = new URL("https://192.168.177.42:8443/");
        HttpsURLConnection urlConnection = (HttpsURLConnection) url.openConnection();
        urlConnection.setSSLSocketFactory(context.getSocketFactory());
        InputStream in = urlConnection.getInputStream();
        in.close();

如果我尝试执行这段代码,我会得到以下异常:

11-13 18:39:02.508  12135-12280/moe.testapp W/System.err﹕ javax.net.ssl.SSLPeerUnverifiedException: Hostname 192.168.177.42 not verified:
11-13 18:39:02.508  12135-12280/moe.testapp W/System.err﹕ certificate: sha1/wFJI0CzwVvJ2MuGvpoJaFO8y4z8=
11-13 18:39:02.508  12135-12280/moe.testapp W/System.err﹕ DN: CN=Alcardis,OU=AL,O=AL,L=test,ST=state,C=XX
11-13 18:39:02.508  12135-12280/moe.testapp W/System.err﹕ subjectAltNames: []
11-13 18:39:02.509  12135-12280/moe.testapp W/System.err﹕ at com.android.okhttp.internal.http.SocketConnector.connectTls(SocketConnector.java:120)
11-13 18:39:02.509  12135-12280/moe.testapp W/System.err﹕ at com.android.okhttp.Connection.connect(Connection.java:143)
11-13 18:39:02.509  12135-12280/moe.testapp W/System.err﹕ at com.android.okhttp.Connection.connectAndSetOwner(Connection.java:185)
11-13 18:39:02.509  12135-12280/moe.testapp W/System.err﹕ at com.android.okhttp.OkHttpClient$1.connectAndSetOwner(OkHttpClient.java:128)
11-13 18:39:02.509  12135-12280/moe.testapp W/System.err﹕ at com.android.okhttp.internal.http.HttpEngine.nextConnection(HttpEngine.java:341)
11-13 18:39:02.509  12135-12280/moe.testapp W/System.err﹕ at com.android.okhttp.internal.http.HttpEngine.connect(HttpEngine.java:330)
11-13 18:39:02.509  12135-12280/moe.testapp W/System.err﹕ at com.android.okhttp.internal.http.HttpEngine.sendRequest(HttpEngine.java:248)
11-13 18:39:02.509  12135-12280/moe.testapp W/System.err﹕ at com.android.okhttp.internal.huc.HttpURLConnectionImpl.execute(HttpURLConnectionImpl.java:433)
11-13 18:39:02.509  12135-12280/moe.testapp W/System.err﹕ at com.android.okhttp.internal.huc.HttpURLConnectionImpl.getResponse(HttpURLConnectionImpl.java:384)
11-13 18:39:02.509  12135-12280/moe.testapp W/System.err﹕ at com.android.okhttp.internal.huc.HttpURLConnectionImpl.getInputStream(HttpURLConnectionImpl.java:231)
11-13 18:39:02.509  12135-12280/moe.testapp W/System.err﹕ at com.android.okhttp.internal.huc.DelegatingHttpsURLConnection.getInputStream(DelegatingHttpsURLConnection.java:210)
11-13 18:39:02.509  12135-12280/moe.testapp W/System.err﹕ at com.android.okhttp.internal.huc.HttpsURLConnectionImpl.getInputStream(HttpsURLConnectionImpl.java)
11-13 18:39:02.509  12135-12280/moe.testapp W/System.err﹕ at moe.testapp.TomcatWebservice.doInBackground(TomcatWebservice.java:64)
11-13 18:39:02.509  12135-12280/moe.testapp W/System.err﹕ at moe.testapp.TomcatWebservice.doInBackground(TomcatWebservice.java:28)
11-13 18:39:02.509  12135-12280/moe.testapp W/System.err﹕ at android.os.AsyncTask$2.call(AsyncTask.java:295)
11-13 18:39:02.509  12135-12280/moe.testapp W/System.err﹕ at java.util.concurrent.FutureTask.run(FutureTask.java:237)
11-13 18:39:02.509  12135-12280/moe.testapp W/System.err﹕ at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:234)
11-13 18:39:02.509  12135-12280/moe.testapp W/System.err﹕ at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1113)
11-13 18:39:02.509  12135-12280/moe.testapp W/System.err﹕ at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:588)
11-13 18:39:02.509  12135-12280/moe.testapp W/System.err﹕ at java.lang.Thread.run(Thread.java:818)

我不明白怎么主机无法验证。证书被正确读取(我至少可以在调试器中使用正确的值访问它)并且 android 应用程序也可以在标准网络浏览器中通过 https 访问 tomcat。


好的,从带有评论的答案中我得到了一些见解并尝试了另一种方法。 服务器没有 FQDN,CN 应该等于 FQND,这就是它在上面的代码中不起作用的原因。

因为服务器没有 FQDN,所以我搜索了使用 ip 地址的替代方法。我找到了这个 howto并创建了一个没有 CN 但具有替代名称的证书并将 ip 放在那里我还必须将行 keystoreType="PKCS12" 添加到 tomcat 的 server.xml 因为我从默认 keystore 更改为PKCS12.

最佳答案

SSL 证书的默认行为是让客户端验证服务器名称是否与证书中的名称匹配。这有助于防止中间人攻击和服务器欺骗。当您的服务器没有名称(192.168.x.x)时,无法进行验证。对于您的初始应用程序,您可以关闭此验证。

您应该为任何实际应用程序保留服务器名称验证。

关于Android SSL 连接到 Tomcat(自签名证书)SSLPeerUnverifiedException,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33699312/

相关文章:

android - 为什么我不应该在 android 中使用 System.out.println()

Android MediaPlayer 仅播放 m3u8 音频流无效

android - 设计 Android EditText 以显示谷歌描述的错误消息

java - 忽略 Apache HTTPClient 4.5 中的自签名证书

java - 在没有 BouncyCaSTLe 的情况下以编程方式为 SSL Client-Auth 创建客户端证书的任何方法?

android - 定位 S+(版本 31 及更高版本)要求在创建 PendingIntent、On AlarmPingSender 时指定 FLAG_IMMUTABLE 或 FLAG_MUTABLE 之一

Wordpress www 到非 www 域迁移

c# - 自托管 C# SSL Web 服务器,无需管理员权限

security - 如何使用独立的 Selenium 服务器测试 https web 应用程序?

google-chrome - 具有大 json 响应的 HTTPS 请求无法下载 [Tomcat]