Java SSL: как отключить проверку имени хоста

Есть ли способ для стандартных сокетов java SSL отключить проверку имени хоста для соединений ssl со свойством? Единственный способ, который я нашел до сих пор, - это написать верификатор имени хоста, который все время возвращает true.

Weblogic предоставляет такую ​​возможность, можно отключить проверку имени хоста с помощью следующего свойства:

-Dweblogic.security.SSL.ignoreHostnameVerify


person paweloque    schedule 17.05.2011    source источник
comment
Что ж, ваше решение, пожалуй, самое чистое, о котором я могу думать; что-то не так с этим?   -  person Piskvor left the building    schedule 17.05.2011
comment
ну, вы просто хотите отключить проверку и сделать это без изменений кода. Обычно у вас есть много свойств для управления ssl-соединениями, но, видимо, не в этом случае...   -  person paweloque    schedule 17.05.2011
comment
ну, вы могли бы создать верификатор имени хоста factory, который проверял бы ваше пользовательское свойство и возвращал фиктивный верификатор Always-ok, если он установлен, или верификатор по умолчанию, если нет; однако это не решает проблему, не так ли?   -  person Piskvor left the building    schedule 17.05.2011
comment
вы правы, это не решает мою проблему. На самом деле я использую не сокеты напрямую, а инфраструктуру веб-сервиса wls, где, кажется, я не на месте водителя, когда дело доходит до конфигурации фабрики сокетов и особенно настройки моего собственного верификатора имени хоста.   -  person paweloque    schedule 17.05.2011


Ответы (5)


Должна быть возможность создать собственный агент Java, который переопределяет значение по умолчанию 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;
            }
        });
    }
}

Затем просто добавьте -javaagent:LenientHostnameVerifierAgent.jar к аргументам запуска программы java.

person Vadzim    schedule 23.10.2012
comment
Это может быть отличным способом справиться с этим, но я имею дело с http-клиентом Apache. Как я могу создать javaagent для установки SSLSocketFactory.setHostnameVerifier(new AllowAllHostnameVerifier())? - person end-user; 13.01.2016
comment
@конечный пользователь, точно так же, как в этом ответе. - person Vadzim; 14.01.2016

Ответ от @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 ());
   }
}
person Markus Heberling    schedule 04.02.2019
comment
Все еще требуется добавить параметр запуска? - person kiltek; 01.11.2019
comment
Когда вы используете опубликованное мной решение, вам не нужны дополнительные параметры запуска. Вам просто нужно убедиться, что фабрика сокетов установлена ​​​​в вашей программе. - person Markus Heberling; 25.11.2019

В стандартных сокетах Java SSL или даже SSL нет проверки имени хоста, поэтому вы не можете установить его на этом уровне. Проверка имени хоста является частью HTTPS (RFC 2818): поэтому она проявляется как javax.net.ssl.HostnameVerifier, который применяется к HttpsURLConnection.

person user207421    schedule 18.05.2011
comment
Это звучит разумно, однако, почему weblogic предоставляет такой переключатель и почему нет такого свойства на уровне HttpsURLConnection? - person paweloque; 18.05.2011
comment
@lewap Я полагаю, это риторические вопросы? Я не могу ответить на вопросы о WebLogic или о том, почему JDK такой, какой он есть. WebLogic выглядит для меня дырой в безопасности, я бы не хотел, чтобы она была в JDK. - person user207421; 18.05.2011
comment
они совсем не риторические, я пытаюсь понять, как работает ssl, и понять различия между jdk и weblogic. Может быть, есть причина для этого. - person paweloque; 18.05.2011
comment
@lewap Конечно, на это есть причина. Вы просто спрашиваете не того человека или не в том месте. - person user207421; 18.05.2011

У меня также была такая же проблема при доступе к веб-сервисам RESTful. И я использую приведенный ниже код, чтобы решить эту проблему:

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

Это сработало для меня. попробуй!!

person Nani    schedule 16.03.2015
comment
Это небезопасно доверяет всем сертификатам, но не обходит проверку имени хоста, поэтому не отвечает на вопрос. - person user207421; 23.12.2016
comment
Не обращайте внимания на комментарий, он обходит hostnameverifier (см. HttpsURLConnection.setDefaultHostnameVerifier(allHostsValid);) - person Frischling; 13.07.2021

Если вы используете http-клиент 4 apache:

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