Игнорировать SSLHandshakeException только для одного конкретного сервера

Мне нужно игнорировать исключение построения пути PKIX

javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException:
PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderExc
ption: unable to find valid certification path to requested target

Я знаю, как это сделать, написав свой собственный класс, реализующий X509TrustManager, где я всегда return true из isServerTrusted.

Но это довольно широко. Мой код станет частью более крупного проекта. Я не хочу, чтобы моя замена доверительного управляющего повлияла на все остальное.

Я всегда буду подключаться к фиксированному доменному имени, например «www.myws.com». Я хочу игнорировать SSLHandshakeException только для подключений к "www.myws.com".

Возможно ли что-то подобное?


person user93353    schedule 25.09.2013    source источник
comment
Это очень похоже на ваш другой вопрос, но, похоже, больше сосредоточено на том, как установить диспетчер доверия для конкретного соединения. Какие библиотеки вы используете?   -  person Bruno    schedule 25.09.2013
comment
@Bruno Это похоже на мой другой вопрос. Но точно не дубликат. Подход к одной и той же проблеме с двух разных сторон. Исключение SSL возникает, когда имя домена не соответствует теме в сертификате. Здесь я пытаюсь фильтровать на основе доменного имени, там я пытаюсь фильтровать на основе темы. Маловероятно, что ответы на 2 вопроса будут одинаковыми, потому что я не думаю, что TrustMananger вообще получает доменное имя сервера. Я думаю, что сравнение доменных имен будет происходить до (или после того, как) TrustManager попросят проверить, подписан ли сертификат доверенным центром сертификации.   -  person user93353    schedule 25.09.2013
comment
Справедливо. Практически невозможно ответить на ваш вопрос без более подробной информации о том, насколько вы контролируете этот клиентский код и какие библиотеки используются.   -  person Bruno    schedule 25.09.2013
comment
Чтобы уточнить, вы не можете «игнорировать SSLHandshakeException». Это фатально для связи. Но вы можете предотвратить это.   -  person user207421    schedule 25.09.2013


Ответы (1)


Маловероятно, что ответы на 2 вопроса будут одинаковыми, потому что я не думаю, что TrustMananger вообще получает доменное имя сервера.

На самом деле, трастовый менеджер может получить имя хоста, которое вы искали. Хотя это зависит от ряда факторов.

  • Давайте просто предположим, что ваши клиенты работают на Java 7.

    Если вы следуете тому же методу, что и в этом другом ответе, но используете X509ExtendedTrustManager (представленный в Java 7, в отличие от простого X509TrustManager), вы получите дополнительные перегруженные методы, которые также дадут вам текущие SSLSocket или SSLEngine.

    SSLContext использует эти методы при инициализации экземпляром X509ExtendedTrustManager, но не когда это обычный X509TrustManager, поэтому он должен проверять тип перед выполнением этих вызовов (см. быстрый тест в конце этого ответа, основанный на код в этом ответе).

    Я не уверен, где это поведение указано в API. Похоже, что в X509ExtendedTrustManager проверке типа. " rel="nofollow noreferrer">Справочное руководство по JSSE. Один из способов убедиться, что расширенные методы используются, — установить указать алгоритм идентификации (например, HTTPS) в вашем SSLParameters, но вам потребуется некоторая степень контроля над клиентским кодом и библиотеками, которые он использует. (Эта функция также появилась в Java 7.)

    Из полученных там SSLSocket или SSLEngine можно получить SSLSession и пир-хост, чтобы там можно было выполнять проверки. (Обратите внимание, что имя хоста может не совсем совпадать с тем, что было задумано, если библиотека, создающая SSLSocket или SSLEngine, не использовала один из методов, который передает это имя как String, а вместо этого передала InetAddress. Вы также потеряете SNI в Это дело.)

    Затем вы можете использовать такой менеджер доверия в вашем SSLContext по умолчанию (с setDefault(...)).

  • Если вы не хотите влиять на SSLContext по умолчанию (разумный выбор для такого рода настроек), вам нужно выяснить, как ваша клиентская библиотека может использовать другой для каждого соединения. Это полностью зависит от того, что используется.

    Для традиционного URLConnection преобразуйте его в HttpsURLConnection и установите SSLSocketFactory как одну сборку из вашего пользовательского SSLContext.


Какие методы будут использоваться, зависит от того, создали ли вы экземпляр X509ExtendedTrustManager или X509TrustManager:

X509TrustManager customTm = new X509ExtendedTrustManager() {
    @Override
    public X509Certificate[] getAcceptedIssuers() {
        return finalTm.getAcceptedIssuers();
    }

    @Override
    public void checkServerTrusted(X509Certificate[] chain,
            String authType) throws CertificateException {
        System.out
                .println("Current method: checkServerTrusted(chain, authType)");
        finalTm.checkServerTrusted(chain, authType);
    }

    //@Override
    public void checkServerTrusted(X509Certificate[] chain,
            String authType, Socket socket) throws CertificateException {
        System.out
                .println("Current method: checkServerTrusted(chain, authType, socket)");
        finalTm.checkServerTrusted(chain, authType, socket);
    }

    //@Override
    public void checkServerTrusted(X509Certificate[] chain,
            String authType, SSLEngine engine)
            throws CertificateException {
        System.out
                .println("Current method: checkServerTrusted(chain, authType, engine)");
        finalTm.checkServerTrusted(chain, authType, engine);
    }

    // Same for client-related methods.
};
person Bruno    schedule 25.09.2013