Android:java.io.IOException:未验证主机名

时间:2014-01-07 11:27:29

标签: android

在运行我的应用程序时遇到java.io.IOException:主机名未经验证,我该如何解决?

java.io.IOException: Hostname '178.61.62.140' was not verified
01-03 16:34:37.613: W/System.err(17118):    at libcore.net.http.HttpConnection.verifySecureSocketHostname(HttpConnection.java:224)
01-03 16:34:37.615: W/System.err(17118):    at libcore.net.http.HttpsURLConnectionImpl$HttpsEngine.connect(HttpsURLConnectionImpl.java:454)
01-03 16:34:37.615: W/System.err(17118):    at libcore.net.http.HttpEngine.sendSocketRequest(HttpEngine.java:282)
01-03 16:34:37.616: W/System.err(17118):    at libcore.net.http.HttpEngine.sendRequest(HttpEngine.java:232)
01-03 16:34:37.617: W/System.err(17118):    at libcore.net.http.HttpURLConnectionImpl.connect(HttpURLConnectionImpl.java:80)
01-03 16:34:37.617: W/System.err(17118):    at libcore.net.http.HttpURLConnectionImpl.getOutputStream(HttpURLConnectionImpl.java:194)
01-03 16:34:37.618: W/System.err(17118):    at libcore.net.http.HttpsURLConnectionImpl.getOutputStream(HttpsURLConnectionImpl.java:280)
01-03 16:34:37.618: W/System.err(17118):    at com.axis.cbk.httpmodel.CustHttpClient.executeHttpPost(CustHttpClient.java:120)
01-03 16:34:37.619: W/System.err(17118):    at com.axis.cbk.MainActivity$ProcessIt.doInBackground(MainActivity.java:237)
01-03 16:34:37.619: W/System.err(17118):    at com.axis.cbk.MainActivity$ProcessIt.doInBackground(MainActivity.java:1)
01-03 16:34:37.621: W/System.err(17118):    at android.os.AsyncTask$2.call(AsyncTask.java:264)
01-03 16:34:37.626: W/System.err(17118):    at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:305)
01-03 16:34:37.626: W/System.err(17118):    at java.util.concurrent.FutureTask.run(FutureTask.java:137)
01-03 16:34:37.627: W/System.err(17118):    at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:208)
01-03 16:34:37.628: W/System.err(17118):    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1076)
01-03 16:34:37.630: W/System.err(17118):    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:569)
01-03 16:34:37.631: W/System.err(17118):    at java.lang.Thread.run(Thread.java:856)
01-03 16:34:37.632: I/System.out(17118): [CDS]close[48194]
01-03 16:34:37.633: I/System.out(17118): close [socket][/0.0.0.0:48194]

3 个答案:

答案 0 :(得分:8)

您正在使用IP地址建立HTTPS连接。现在,SSL证书绑定到DNS主机名,并且由于您没有使用DNS主机名进行连接,因此无法验证证书。

使用实际的DNS名称进行连接,或者在极少数情况下使用接受主机的write your own hostname verifier(注意:在那里引入漏洞非常容易)。

答案 1 :(得分:2)

@ laalto在他的回答中提出了一些好处。还有一个替代解决方法,我不需要对您的Android代码进行任何更改,我已在下面概述。

tl; dr - 修改Android设备上的/ etc / hosts文件,并添加一个新条目,将自签名证书通用名称映射到开发服务器的IP地址。

我已经概述了以下完整的流程......

像往常一样创建证书:

    sudo openssl genrsa -out key.pem 2048
    sudo openssl req -new -x509 -key key.pem -out cert.pem -days 1095
    sudo cat key.pem cert.pem >> stunnel.pem

在第二个命令中,将公共名称设置为您想要的任何域名,对于此示例,我将使用 testssl.com

我使用stunnel代理我的ssl连接,因此第3个命令可能不适用。无论如何,一旦您的测试网站使用您刚刚创建的证书,请在桌面上打开浏览器并导航到您的站点。正如您所期望的那样,如果一切都按预期进行,您应该收到安全警告。查看证书并将其导出为带链(PEM)的 X.509证书。假设我们将其保存为 testssl.com

现在运行以下命令将其从PEM格式转换为可以下载到Android设备上的证书格式。

    openssl x509 -inform PEM -outform DM -in testssl.com -out testssl.com.crt

使用adb,您现在可以将证书推送到您的设备上。

    adb push testssl.com.crt /sdcard/testssl.com.crt

在您的Android设备上,转到设置 - >安全性 - >从设备存储安装。您应该看到您提供证书的名称,对我来说, testssl.com.crt

要修改你的/ etc / hosts文件,你需要将你的/ system分区重新安装为读写,不幸的是你需要su。

    adb shell
    su    
    mount -o rw,remount /system

我们将/ system分区放回以后再读取。

现在让我们抓住hosts文件,对其进行修改,然后使用以下命令将其重新放回设备。

    adb shell
    su
    dd if=/etc/hosts of=/sdcard/hosts
    exit
    exit
    adb pull /sdcard/hosts

您现在可以在主机文件中添加一行,使其看起来像 [development_server_ip_address] [domain_name] 。因此,假设我使用上面详述的设置并且我的开发服务器的IP为192.168.1.10,那么我将以下行添加到我的主机文件中:

    192.168.1.10     testssl.com

现在,您可以在运行以下命令后使用已修改的主机文件。

    adb push hosts /sdcard/hosts
    adb shell
    su
    dd if=/sdcard/hosts of=/etc/hosts

要使/ system分区只读,请从adb shell运行以下命令。

    mount -o ro,remount /system

现在,您的Android应用以及使用HTTPSUrlConnection对象连接到您在hosts文件中添加的域名的任何其他应用,都不应该收到任何证书错误。最重要的是,你没有必要改变一行代码。

答案 2 :(得分:0)

请注意,SSL证书只能通过域工作,不能按IP地址工作。

如果您使用IP,请在代码

下面插入
HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier()
        {
            @Override
            public boolean verify(String hostname, SSLSession session)
            {
                if(hostname.equals("127.0.0.1 << your IP"))
                     return true;
            }
        });