java主机名错误异常
我把主机名搞错了。我在程序中使用了this code(从某个链接获得)。我的程序运行良好。我的问题是它足够安全吗??(因为它不是在验证证书链)
public class Host {
public String subscribe() throws Exception {
String resp = "";
String urlString="https://xxx.xxx.xx.xx:8443/WebApplication3/NewServlet";
URL url;
URLConnection urlConn;
DataOutputStream printout;
DataInputStream input;
String str = "";
int flag=1;
try {
HostnameVerifier hv = new HostnameVerifier() {
public boolean verify(String urlHostName, SSLSession session) {
System.out.println("Warning: URL Host: " + urlHostName + " vs. "
+ session.getPeerHost());
return true;
}
};
trustAllHttpsCertificates();
HttpsURLConnection.setDefaultHostnameVerifier(hv);
url = new URL(urlString);
urlConn = url.openConnection();
urlConn.setDoInput(true);
Object object;
urlConn.setUseCaches(false);
urlConn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
input = new DataInputStream(urlConn.getInputStream());
while (null != ((str = input.readLine()))) {
if (str.length() >0) {
str = str.trim();
if(!str.equals("")) {
//System.out.println(str);
resp += str;
}
}
}
input.close();
} catch ( MalformedURLException mue) {
mue.printStackTrace();
} catch(IOException ioe) {
ioe.printStackTrace();
}
return resp;
}
public static class miTM implements javax.net.ssl.TrustManager,
javax.net.ssl.X509TrustManager {
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
return null;
}
public boolean isServerTrusted(java.security.cert.X509Certificate[] certs) {
return true;
}
public boolean isClientTrusted(java.security.cert.X509Certificate[] certs) {
return true;
}
public void checkServerTrusted(java.security.cert.X509Certificate[] certs, String authType) throws java.security.cert.CertificateException {
return;
}
public void checkClientTrusted(java.security.cert.X509Certificate[] certs, String authType) throws java.security.cert.CertificateException {
return;
}
}
private static void trustAllHttpsCertificates() throws Exception {
// Create a trust manager that does not validate certificate chains:
javax.net.ssl.TrustManager[] trustAllCerts = new javax.net.ssl.TrustManager[1];
javax.net.ssl.TrustManager tm = new miTM();
trustAllCerts[0] = tm;
javax.net.ssl.SSLContext sc = javax.net.ssl.SSLContext.getInstance("SSL");
sc.init(null, trustAllCerts, null);
javax.net.ssl.HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
}
}
# 1 楼答案
下面是一种清理代码并保持安全的方法。我想代码连接到一个已知的服务(受信任的)。要使Java SSL堆栈即使在主机名不匹配的情况下也接受连接,最好的方法是将服务器证书添加到JVM信任存储中
首先,您可以从浏览器中导出服务器证书并将其保存在磁盘上。在Linux中,您可以使用
openssl s_client -connect xxx.xxx.xx.xx:8443
并将ascii格式的服务器证书复制/粘贴到文本文件中然后使用keytool将服务器证书导入
jre/lib/security/cacerts
JKS文件我更喜欢的另一种选择是,在更新Java时避免回归,即在自己的位置复制
cacerts
,并通过javax.net.ssl.trustStore
系统属性声明它由于服务器证书位于信任存储中。。。它是受信任的,直到过期。这通常用于自签名服务器证书
# 2 楼答案
miTM
中的代码实际上禁用了任何SSL安全检查,因此安全级别非常低(只有SSL证书损坏时才会出错,但当证书与域不匹配时不会出错)基本上,你试图在没有任何安全措施的情况下建立连接。如果这就是你想要的,解决方案可能是“足够安全”,但答案很可能是“不”
这种问题的正确解决方案是为此域创建匹配的证书
不幸的是,当HTTP服务器使用“虚拟主机”(许多域名映射到同一IP地址)时,这是不可能的。解决这个问题的正确方法是获取自己的IP地址
如果您仍然想尝试纯Java的解决方案,请查看以下答案:https://stackoverflow.com/a/3293720/34088
# 3 楼答案
在java中,很多时候都会遇到这样的异常
问题可能是ipconflict/ip域不匹配/证书无效
我已经通过使用其适当的ip地址和安装证书解决了这个问题
# 4 楼答案
要确保连接安全,您必须(至少):
您的代码在这两点上失败:
TrustManager
根本不检查证书(它从不抛出异常,而API希望它在证书不受信任时抛出CertificateException
形式)李>true
李>要修复代码:
TrustManagerFactory
初始化它们李>问题的标题(“em>主机名错误异常”)和示例URL
https://xxx.xxx.xx.xx:8443
似乎表明您正在连接IP地址与某些浏览器不同,Java严格遵循规范(RFC 2818):
这意味着您不能仅仅将IP地址放在服务器证书中的主题DN的通用名(CN)中。如果您使用的是IP地址,必须在主题替代名称条目中。(从Java 7开始,
keytool
有生成此类证书的选项。)您将找到有关在this answer中使用哪些命令的更多详细信息
也就是说,使用IP地址最多只能在测试环境中工作。我不认为任何商业CA会给你一个基于IP地址的证书。我建议设置DNS条目(即使它只是在测试环境中的
hosts
文件中)即使您没有使用IP地址,也必须确保该证书对您试图与服务器联系的主机名有效:如果您有Subject Alternative name条目,其中一个条目必须与主机名匹配;否则,主机名必须位于此证书的主题DN的CN RDN中