安卓:java.io.IOException: 主机名未经验证

6
在运行我的应用程序时,出现了java.io.IOException: Hostname was not verified的错误,我该如何解决它?
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]

请参考以下链接:https://dev59.com/PGUq5IYBdhLWcg3wSelm 和 http://stackoverflow.com/questions/19157710/hostname-was-not-verified-android - Shayan Pourvatan
user2805994,请不要自我破坏你的问题。 - laalto
3个回答

8
你正在使用IP地址进行HTTPS连接。现在,SSL证书绑定到DNS主机名上,因为你没有使用DNS主机名进行连接,所以无法验证证书。
请使用实际的DNS名称进行连接,或在某些罕见情况下,编写自己的主机名验证器,接受你的主机(小心:很容易引入漏洞)。

使用DNS后,出现java.net.UnknownHostException错误:无法解析主机“******.com”:主机名没有关联的地址。 - devel
哇,我已经试图修复那个问题一个星期了,非常感谢。只是提醒一下,如果你在代码中使用IP地址,最简单的解决方案是在IP地址末尾添加“nip.io”(或类似的网站)-它看起来像这样:“your_IP.nip.io”,并且可以完美地工作。 - adek111

2

@laalto在他的回答中提出了一些好观点。此外,我还提供了一种替代方法,不需要对您的Android代码进行任何更改,如下所述。

简而言之- 修改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连接,因此第三个命令可能不适用。无论如何,一旦您的测试网站使用了您刚创建的证书,就在桌面上打开浏览器并导航到您的网站。正如您所预期的那样,如果一切都按照预期进行,您应该会收到安全警告。查看证书并将其导出为X.509证书链(PEM)。我们将其保存为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

现在您可以在hosts文件中添加一行,使其类似于[开发服务器IP地址] [域名]。假设我使用了上面详细介绍的设置,我的dev服务器的IP地址是192.168.1.10,则我应该将以下行添加到我的hosts文件中:

    192.168.1.10     testssl.com

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

    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文件中添加的域名的应用程序,都不应该收到任何证书错误。最重要的是,您不需要更改任何代码。

1
请注意,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;
            }
        });

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