Java SSL:如何禁用主机名验证
标准java SSL套接字是否有办法禁用具有属性的SSL连接的主机名验证?到目前为止,我找到的唯一方法是编写一个主机名验证程序,它始终返回true Weblogic提供了这种可能性,可以使用以下属性禁用主机名验证:Java SSL:如何禁用主机名验证,java,ssl,ssl-certificate,hostname,Java,Ssl,Ssl Certificate,Hostname,标准java SSL套接字是否有办法禁用具有属性的SSL连接的主机名验证?到目前为止,我找到的唯一方法是编写一个主机名验证程序,它始终返回true Weblogic提供了这种可能性,可以使用以下属性禁用主机名验证: -Dweblogic.security.SSL.ignoreHostnameVerify标准JavaSSL套接字或SSL中没有主机名验证,因此无法将其设置为该级别。主机名验证是HTTPS(RFC 2818)的一部分:这就是为什么它显示为javax.net.ssl.HostnameVe
-Dweblogic.security.SSL.ignoreHostnameVerify标准JavaSSL套接字或SSL中没有主机名验证,因此无法将其设置为该级别。主机名验证是HTTPS(RFC 2818)的一部分:这就是为什么它显示为javax.net.ssl.HostnameVerifier,应用于HttpsURLConnection。应该可以创建覆盖默认主机名验证程序的自定义设置:
import javax.net.ssl.*;
import java.lang.instrument.Instrumentation;
public class LenientHostnameVerifierAgent {
public static void premain(String args, Instrumentation inst) {
HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() {
public boolean verify(String s, SSLSession sslSession) {
return true;
}
});
}
}
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.Socket;
import java.net.URL;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.X509Certificate;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLEngine;
import javax.net.ssl.SSLHandshakeException;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509ExtendedTrustManager;
public class Test {
public static void main (String [] args) throws IOException {
// This URL has a certificate with a wrong name
URL url = new URL ("https://wrong.host.badssl.com/");
try {
// opening a connection will fail
url.openConnection ().connect ();
} catch (SSLHandshakeException e) {
System.out.println ("Couldn't open connection: " + e.getMessage ());
}
// Bypassing the SSL verification to execute our code successfully
disableSSLVerification ();
// now we can open the connection
url.openConnection ().connect ();
System.out.println ("successfully opened connection to " + url + ": " + ((HttpURLConnection) url.openConnection ()).getResponseCode ());
}
// Method used for bypassing SSL verification
public static void disableSSLVerification () {
TrustManager [] trustAllCerts = new TrustManager [] {new X509ExtendedTrustManager () {
@Override
public void checkClientTrusted (X509Certificate [] chain, String authType, Socket socket) {
}
@Override
public void checkServerTrusted (X509Certificate [] chain, String authType, Socket socket) {
}
@Override
public void checkClientTrusted (X509Certificate [] chain, String authType, SSLEngine engine) {
}
@Override
public void checkServerTrusted (X509Certificate [] chain, String authType, SSLEngine engine) {
}
@Override
public java.security.cert.X509Certificate [] getAcceptedIssuers () {
return null;
}
@Override
public void checkClientTrusted (X509Certificate [] certs, String authType) {
}
@Override
public void checkServerTrusted (X509Certificate [] certs, String authType) {
}
}};
SSLContext sc = null;
try {
sc = SSLContext.getInstance ("SSL");
sc.init (null, trustAllCerts, new java.security.SecureRandom ());
} catch (KeyManagementException | NoSuchAlgorithmException e) {
e.printStackTrace ();
}
HttpsURLConnection.setDefaultSSLSocketFactory (sc.getSocketFactory ());
}
}
然后只需将
-javaagent:LenientHostnameVerifierAgent.jar
添加到程序的java启动参数中。在访问RESTful web服务时,我也遇到了同样的问题。我用下面的代码来解决这个问题:
public class Test {
//Bypassing the SSL verification to execute our code successfully
static {
disableSSLVerification();
}
public static void main(String[] args) {
//Access HTTPS URL and do something
}
//Method used for bypassing SSL verification
public static void disableSSLVerification() {
TrustManager[] trustAllCerts = new TrustManager[] { new X509TrustManager() {
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
return null;
}
public void checkClientTrusted(X509Certificate[] certs, String authType) {
}
public void checkServerTrusted(X509Certificate[] certs, String authType) {
}
} };
SSLContext sc = null;
try {
sc = SSLContext.getInstance("SSL");
sc.init(null, trustAllCerts, new java.security.SecureRandom());
} catch (KeyManagementException e) {
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
HostnameVerifier allHostsValid = new HostnameVerifier() {
public boolean verify(String hostname, SSLSession session) {
return true;
}
};
HttpsURLConnection.setDefaultHostnameVerifier(allHostsValid);
}
}
这对我有用。试试看 如果您正在使用apache的http客户端4:
SSLConnectionSocketFactory sslConnectionSocketFactory =
new SSLConnectionSocketFactory(sslContext,
new String[] { "TLSv1.2" }, null, new HostnameVerifier() {
public boolean verify(String arg0, SSLSession arg1) {
return true;
}
});
来自@Nani的答案不再适用于Java1.8u181。您仍然需要使用自己的TrustManager,但它需要是
X509ExtendedTrustManager
而不是X509TrustManager
:
import javax.net.ssl.*;
import java.lang.instrument.Instrumentation;
public class LenientHostnameVerifierAgent {
public static void premain(String args, Instrumentation inst) {
HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() {
public boolean verify(String s, SSLSession sslSession) {
return true;
}
});
}
}
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.Socket;
import java.net.URL;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.X509Certificate;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLEngine;
import javax.net.ssl.SSLHandshakeException;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509ExtendedTrustManager;
public class Test {
public static void main (String [] args) throws IOException {
// This URL has a certificate with a wrong name
URL url = new URL ("https://wrong.host.badssl.com/");
try {
// opening a connection will fail
url.openConnection ().connect ();
} catch (SSLHandshakeException e) {
System.out.println ("Couldn't open connection: " + e.getMessage ());
}
// Bypassing the SSL verification to execute our code successfully
disableSSLVerification ();
// now we can open the connection
url.openConnection ().connect ();
System.out.println ("successfully opened connection to " + url + ": " + ((HttpURLConnection) url.openConnection ()).getResponseCode ());
}
// Method used for bypassing SSL verification
public static void disableSSLVerification () {
TrustManager [] trustAllCerts = new TrustManager [] {new X509ExtendedTrustManager () {
@Override
public void checkClientTrusted (X509Certificate [] chain, String authType, Socket socket) {
}
@Override
public void checkServerTrusted (X509Certificate [] chain, String authType, Socket socket) {
}
@Override
public void checkClientTrusted (X509Certificate [] chain, String authType, SSLEngine engine) {
}
@Override
public void checkServerTrusted (X509Certificate [] chain, String authType, SSLEngine engine) {
}
@Override
public java.security.cert.X509Certificate [] getAcceptedIssuers () {
return null;
}
@Override
public void checkClientTrusted (X509Certificate [] certs, String authType) {
}
@Override
public void checkServerTrusted (X509Certificate [] certs, String authType) {
}
}};
SSLContext sc = null;
try {
sc = SSLContext.getInstance ("SSL");
sc.init (null, trustAllCerts, new java.security.SecureRandom ());
} catch (KeyManagementException | NoSuchAlgorithmException e) {
e.printStackTrace ();
}
HttpsURLConnection.setDefaultSSLSocketFactory (sc.getSocketFactory ());
}
}
嗯,你的解决方案几乎是我能想到的最干净的解决方案;它有什么问题吗?嗯,您只想禁用检查,并且在不更改代码的情况下执行此操作。通常,您有很多属性来控制ssl连接,但显然不是在这种情况下……好吧,您可以创建一个主机名验证器工厂,该工厂将检查您的自定义属性,并返回“始终正常”的虚拟验证器(如果已设置),或者返回默认验证器(如果未设置);然而,这并不能真正解决问题,不是吗?你是对的,这并不能解决我的问题。事实上,我并没有直接使用套接字,而是wls webservice框架,在这里,当涉及套接字工厂配置时,尤其是设置我自己的主机名验证器时,我似乎不在驾驶座上。不过,这听起来很合理,为什么weblogic提供这样一个开关,为什么HttpsURLConnection级别上没有这样的属性?@lewap我想这些问题都是修辞性的?我无法回答有关WebLogic的问题,也无法回答关于JDK为何如此的问题。WebLogic在我看来像是一个安全漏洞,我不希望它出现在JDK中。它们根本不是修辞性的,我试图理解ssl是如何工作的,并理解JDK和WebLogic之间的区别。也许这是有原因的。@lewap当然有原因。这可能是一个很好的处理方法,但我正在处理Apache的http客户端。如何创建javaagent来设置
SSLSocketFactory.setHostnameVerifier(新的AllowAllHostnameVerifier())
?@end-user,与此答案中的方法相同。这不安全地信任所有证书,但不会绕过主机名验证,所以它没有回答这个问题。它仍然需要添加一个启动参数吗?当你使用我发布的解决方案时,你不需要任何额外的启动参数。您只需要确保在程序中设置了套接字工厂。