OkHttp 3(Android):使用自签名SSL连接IP地址

3
我正在尝试连接到一个没有域名,只能通过IP地址访问的服务器。我之前尝试使用volley库来完成它,但是经过一天的研究,我无法弄清为什么SSL握手不起作用。切换到Okhttp后,我收到了警告:
javax.net.ssl.SSLPeerUnverifiedException:未验证主机名185.101.92.193: 证书:sha256 / QMgPlAslWrBi1dd / P17AKxJCniO2RfHQ5MufVO5Xji4 = DN:1.2.840.113549.1.9.1 =#1619626c61636b6a61636b34323636323440676d61696c2e636f6d,CN = 185.101.92.193,O = Internet Widgits Pty Ltd,L = Berlin,ST = Berlin,C = DE subjectAltNames:[]
现在这个问题已经在github上得到解决:https://github.com/square/okhttp/issues/1467 我用以下代码“解决”了这个问题(请看下面的HostnameVerifier):
// loading CAs from an InputStream
        try {
            CertificateFactory cf = CertificateFactory.getInstance("X.509");
            InputStream cert = context.getResources().openRawResource(R.raw.servercert);
            Certificate ca;
            try {
                ca = cf.generateCertificate(cert);
            } finally {
                cert.close();
            }

            // creating a KeyStore containing our trusted CAs
            String keyStoreType = KeyStore.getDefaultType();
            KeyStore keyStore = KeyStore.getInstance(keyStoreType);
            keyStore.load(null, null);
            keyStore.setCertificateEntry("ca", ca);

            // creating a TrustManager that trusts the CAs in our KeyStore
            String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
            TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmfAlgorithm);
            tmf.init(keyStore);

            // creating an SSLSocketFactory that uses our TrustManager
            SSLContext sslContext = SSLContext.getInstance("TLS");
            sslContext.init(null, tmf.getTrustManagers(), null);
            client = new OkHttpClient.Builder().sslSocketFactory(sslContext.getSocketFactory())
                    .hostnameVerifier(new HostnameVerifier() {
                        @Override
                        public boolean verify(String s, SSLSession sslSession) {
                            if(s.equals(myIPAddress)){
                                return true;
                            }else{
                                return false;
                            }
                        }
                    })
                    .build();
        }catch (Exception e){
            e.printStackTrace();
        }

现在这似乎是个不好的做法,我的实际问题是:如果像这样实现HostnameVerifier可能会出现什么安全问题,并且我该如何以更复杂的方式解决这个问题?

你可以为服务器获取一个域名。域名相当便宜。 - CommonsWare
是的,你说得有道理。但是我仍然会等待,看看是否有人能告诉我为什么我不应该做我在这里做的事情,为了学习的缘故。 - Doflaminhgo
1个回答

2
与域名无关,唯一的问题是您的应用程序(Android)无法验证证书,因为它是私有的(自签名证书)。您在代码中所做的只是尝试通过覆盖SSLFactory并创建一个使用您的CAs的新SSLFactory来绕过验证过程。 请查看以下Android文档: https://developer.android.com/training/articles/security-ssl.html#CommonProblems 您可以继续使用当前的方法,或者购买证书,这样就完全不需要此代码了。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接