Как я могу использовать локальный HTTPS URL в Java? - PullRequest
9 голосов
/ 17 декабря 2008

Используя класс URL Java, я могу подключиться к внешнему HTTPS серверу (например, нашему производственному сайту), но используя локальный URL, я получаю следующее исключение.

"SunCertPathBuilderException: unable to find valid certification path to requested target".

Как мне получить действительный путь сертификации?

РЕДАКТИРОВАТЬ: я не использую этот URL-адрес для непосредственного создания соединения, я передаю URL-адрес itext PDFReader, который затем имеет проблему с подключением.

Ответы [ 6 ]

13 голосов
/ 13 мая 2009

Вот мое решение, которое включает в себя некоторые идеи в этой теме и дополнено кодом из сети. Все, что я делаю, вызывает эту функцию, и она устанавливает Менеджер доверия по умолчанию и HostName Verifier для HttpsURLConnection. Это может быть нежелательно для некоторых, потому что это повлияет на все соединения HttpsURLC, но я просто пишу простой прокси, чтобы он работал для меня.

private void setTrustAllCerts() throws Exception
{
    TrustManager[] trustAllCerts = new TrustManager[]{
        new X509TrustManager() {
            public java.security.cert.X509Certificate[] getAcceptedIssuers() {
                return null;
            }
            public void checkClientTrusted( java.security.cert.X509Certificate[] certs, String authType ) { }
            public void checkServerTrusted( java.security.cert.X509Certificate[] certs, String authType ) { }
        }
    };

    // Install the all-trusting trust manager
    try {
        SSLContext sc = SSLContext.getInstance( "SSL" );
        sc.init( null, trustAllCerts, new java.security.SecureRandom() );
        HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
        HttpsURLConnection.setDefaultHostnameVerifier( 
            new HostnameVerifier() {
                public boolean verify(String urlHostName, SSLSession session) {
                    return true;
                }
            });
    }
    catch ( Exception e ) {
        //We can not recover from this exception.
        e.printStackTrace();
    }
}
3 голосов
/ 17 декабря 2008

Другая вещь, на которую стоит обратить внимание - это TrustManager, который вы используете. Сообщение об ошибке предполагает, что сертификат, представленный сервером, не подписан доверенным корнем. Поскольку у вас нет прямого контроля над созданным сокетом SSL, я думаю, что вам лучше всего инициализировать свои SSLContext с TrustManager, которые были настроены с корнем CA цепочки сертификатов сервера. Затем установите этот контекст как default .

Это предполагает, что вы используете Java 6. API более ограничен в Java 5. Вы можете получить значение по умолчанию SSLSocketFactory, но стандартного способа установить его нет.

3 голосов
/ 17 декабря 2008

Возможно, вам нужно настроить HostnameVerifier. Перед подключением необходимо добавить его в объект подключения

HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();
conn.setHostnameVerifier(new HostnameVerifier() {
  public boolean verify(String hostname, SSLSession session) {
    // check hostname/session
    return true;
  }
});
conn.connect();
// read/write...

Конечно, есть некоторые реализации, если они вам нужны. Возможно, вы захотите взглянуть и на проект HttpClient .

0 голосов
/ 18 декабря 2008

В итоге я запустил статический метод (только для dev), который устанавливает очень доверяющий TrustManager (принимает все), а также добавил hostnameVerifier, который всегда возвращает true (спасибо sblundy ).

0 голосов
/ 17 декабря 2008

Это также может помочь вам добавить сертификат, который использует сервер localhost (я полагаю, он самоподписан) в хранилище ключей JVM , с помощью утилиты "keytool" . Это должно привести к тому, что JVM скажет: «Вы можете доверять этому сертификату».

0 голосов
/ 17 декабря 2008

Проблема, на которую он жалуется, заключается в том, что при создании соединения SSL сервер должен предоставить действительный сертификат клиенту. Вы можете написать соответствующую конечную точку на Java (я думаю, HTTPServerSocket сделает это), но для ее установки потребуется взломать. Вероятно, проще настроить локальный веб-сервер с чем-нибудь, что правильно обрабатывает SSL - Apache, lighttp, что угодно - и создать самоподписанный сертификат с помощью инструментов openssl. обновленный

Вот пример из альманаха Java. http://www.exampledepot.com/egs/javax.net.ssl/Server.html

Для сокета сервера SSL требуются сертификаты, которые он будет отправлять клиентам для аутентификации. Сертификаты должны содержаться в хранилище ключей, местоположение которого должно быть явно указано (по умолчанию нет). Следуя примеру, мы опишем, как создать и указать хранилище ключей для сокета сервера SSL для использования.

try {
    int port = 443;
    ServerSocketFactory ssocketFactory = SSLServerSocketFactory.getDefault();
    ServerSocket ssocket = ssocketFactory.createServerSocket(port);

    // Listen for connections
    Socket socket = ssocket.accept();

    // Create streams to securely send and receive data to the client
    InputStream in = socket.getInputStream();
    OutputStream out = socket.getOutputStream();

    // Read from in and write to out...

    // Close the socket
    in.close();
    out.close();
} catch(IOException e) {
}

Укажите хранилище ключей сертификатов, используя системное свойство javax.net.ssl.keyStore:

> java -Djavax.net.ssl.keyStore=mySrvKeystore -Djavax.net.ssl.keyStorePassword=123456 MyServer
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...