在运行我的应用程序时遇到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]
答案 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;
}
});