Java SSL:如何禁用主机名验证

发布于 2024-11-08 07:09:14 字数 180 浏览 1 评论 0原文

标准 java SSL 套接字是否可以通过属性禁用 ssl 连接的主机名验证?到目前为止我发现的唯一方法是编写一个始终返回 true 的主机名验证器。

Weblogic 提供了这种可能性,可以使用以下属性禁用主机名验证:

-Dweblogic.security.SSL.ignoreHostnameVerify

Is there a way for the standard java SSL sockets to disable hostname verfication for ssl connections with a property? The only way I found until now, is to write a hostname verifier which returns true all the time.

Weblogic provides this possibility, it is possible to disable the hostname verification with the following property:

-Dweblogic.security.SSL.ignoreHostnameVerify

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

伴我老 2024-11-15 07:09:15

应该可以创建覆盖默认 HostnameVerifier 的自定义 java 代理

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;
            }
        });
    }
}

然后只需将 -javaagent:LenientHostnameVerifierAgent.jar 添加到程序的 java 启动参数中即可。

It should be possible to create custom java agent that overrides default HostnameVerifier:

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;
            }
        });
    }
}

Then just add -javaagent:LenientHostnameVerifierAgent.jar to program's java startup arguments.

别忘他 2024-11-15 07:09:15

@Nani 的答案不再适用于 Java 1.8u181。您仍然需要使用自己的 TrustManager,但它需要是 X509ExtendedTrustManager 而不是 X509TrustManager

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 ());
   }
}

The answer from @Nani doesn't work anymore with Java 1.8u181. You still need to use your own TrustManager, but it needs to be a X509ExtendedTrustManager instead of a X509TrustManager:

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 ());
   }
}
可爱咩 2024-11-15 07:09:15

标准 Java SSL 套接字或 SSL 中没有主机名验证,因此您无法将其设置为该级别。主机名验证是 HTTPS (RFC 2818) 的一部分:这就是为什么它表现为 javax.net.ssl.HostnameVerifier,它应用于 HttpsURLConnection。

There is no hostname verification in standard Java SSL sockets or indeed SSL, so that's why you can't set it at that level. Hostname verification is part of HTTPS (RFC 2818): that's why it manifests itself as javax.net.ssl.HostnameVerifier, which is applied to an HttpsURLConnection.

温柔少女心 2024-11-15 07:09:15

我在访问 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);           
    }
}

它对我有用。试试吧!

I also had the same problem while accessing RESTful web services. And I their with the below code to overcome the issue:

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);           
    }
}

It worked for me. try it!!

落花随流水 2024-11-15 07:09:15

@user207421 是对的,标准 Java SSL 套接字或 SSL 中没有主机名验证。

但是 X509ExtendedTrustManager 实现主机名检查逻辑(参见 javadoc)。要禁用此功能,我们可以将 SSLParameters .endpointIdentificationAlgorithm 设置为 null 作为 JDK AbstractAsyncSSLConnection 做了:

        if (!disableHostnameVerification)
            sslParameters.setEndpointIdentificationAlgorithm("HTTPS"); // default is null

disableHostnameVerification 从属性中读取:jdk.internal.httpclient.disableHostnameVerification。

如何修改 SSLParameters 对象取决于您使用的指定软件。

如 spring webflux WebClient:

HttpClient httpClient = HttpClient.create()
    .secure(sslContextSpec ->
        sslContextSpec
            .sslContext(sslContext)
            .handlerConfigurator(sslHandler -> {
                SSLEngine engine = sslHandler.engine();
                SSLParameters newSslParameters = engine.getSSLParameters(); // 返回的是一个新对象
                // 参考:https://github.com/AdoptOpenJDK/openjdk-jdk11/blob/master/src/java.net.http/share/classes/jdk/internal/net/http/AbstractAsyncSSLConnection.java#L116
                newSslParameters.setEndpointIdentificationAlgorithm(null);
                engine.setSSLParameters(newSslParameters);
            })
    )
    
WebClient webclient = WebClient.builder()
                .clientConnector(new ReactorClientHttpConnector(httpClient))
                .build();

@user207421 is right, there is no hostname verification in standard Java SSL sockets or indeed SSL.

But X509ExtendedTrustManager implement the host name check logic(see it's javadoc). To disable this, We can set SSLParameters .endpointIdentificationAlgorithm to null as JDK AbstractAsyncSSLConnection did:

        if (!disableHostnameVerification)
            sslParameters.setEndpointIdentificationAlgorithm("HTTPS"); // default is null

disableHostnameVerification is read from property: jdk.internal.httpclient.disableHostnameVerification。

How to modify SSLParameters Object is dependends on the specify soft you use。

as spring webflux WebClient:

HttpClient httpClient = HttpClient.create()
    .secure(sslContextSpec ->
        sslContextSpec
            .sslContext(sslContext)
            .handlerConfigurator(sslHandler -> {
                SSLEngine engine = sslHandler.engine();
                SSLParameters newSslParameters = engine.getSSLParameters(); // 返回的是一个新对象
                // 参考:https://github.com/AdoptOpenJDK/openjdk-jdk11/blob/master/src/java.net.http/share/classes/jdk/internal/net/http/AbstractAsyncSSLConnection.java#L116
                newSslParameters.setEndpointIdentificationAlgorithm(null);
                engine.setSSLParameters(newSslParameters);
            })
    )
    
WebClient webclient = WebClient.builder()
                .clientConnector(new ReactorClientHttpConnector(httpClient))
                .build();
孤云独去闲 2024-11-15 07:09:15

如果您使用 apache 的 http-client 4:

SSLConnectionSocketFactory sslConnectionSocketFactory = 
    new SSLConnectionSocketFactory(sslContext,
             new String[] { "TLSv1.2" }, null, new HostnameVerifier() {
                    public boolean verify(String arg0, SSLSession arg1) {
                            return true;
            }
      });

In case you're using apache's http-client 4:

SSLConnectionSocketFactory sslConnectionSocketFactory = 
    new SSLConnectionSocketFactory(sslContext,
             new String[] { "TLSv1.2" }, null, new HostnameVerifier() {
                    public boolean verify(String arg0, SSLSession arg1) {
                            return true;
            }
      });
她比我温柔 2024-11-15 07:09:15

禁用检查主机名:

sslContextFactory.setHostnameVerifier(new NoopHostnameVerifier());

Disable check hostname:

sslContextFactory.setHostnameVerifier(new NoopHostnameVerifier());
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文