Как я могу получить отладочные сообщения из SSL-рукопожатия Java?

Я пытаюсь защитить службу REST Java Spring Boot с помощью Keycloak. Частично это включает в себя связь между сервисом и Keycloak для получения известной конфигурации OpenID.

Когда все не зашифровано (через HTTP), все работает нормально. Когда я добавляю сертификат SSL в смесь (технически на сервере nginx перед обеими службами), я получаю ошибку рукопожатия SSL.

Если я попаду в службу REST или Keycloak напрямую в своем браузере, браузер не сообщит об ошибке SSL. Использование curl с остального сервера на машине Keycloak также выглядит нормально, и я попытался заставить nginx заставить ответ TLS 1.2 или 1.3.

Ошибка, когда реальная служба REST пытается подключиться к службе Keycloak, выглядит так:

2022-03-21 19:30:59.526  WARN 27 --- [nio-8080-exec-3] o.keycloak.adapters.KeycloakDeployment   : Failed to load URLs from https://.../auth/realms/MyRealm/.well-known/openid-configuration

javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure
        at java.base/sun.security.ssl.Alert.createSSLException(Alert.java:131) ~[na:na]
...

Я просматривал множество других ответов, таких как этот один, но я не могу заставить службу распечатать какую-либо отладочную информацию, кроме фактического исключения. Я пробовал:

  • Добавление -Djavax.net.debug=ssl в командную строку, которая запускает сервер
  • Добавление System.setProperty("javax.net.debug", "ssl"); в функцию main() приложения
  • Добавление logging.level.javax=TRACE и logging.level.net=TRACE в application.properties

Ничто меня никуда не ведет. Вывод по-прежнему имеет конец запуска сервера

2022-03-21 19:30:34.219  INFO 27 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet        : Initializing Servlet 'dispatcherServlet'
2022-03-21 19:30:34.221  INFO 27 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet        : Completed initialization in 2 ms

затем сообщение об ошибке

2022-03-21 19:30:59.526  WARN 27 --- [nio-8080-exec-3] o.keycloak.adapters.KeycloakDeployment   : Failed to load URLs from https://.../auth/realms/MyRealm/.well-known/openid-configuration

Как мне включить отладку, чтобы я мог выяснить, где происходит сбой рукопожатия?

---- РЕДАКТИРОВАТЬ ----

Удалось включить ведение журнала отладки - как следует из комментария ниже, пришлось добавить подкатегорию, например.

System.setProperty("javax.net.debug", "ssl:handshake");

Это производит массу вывода, я не уверен, что вижу большую часть этого полезным:

javax.net.ssl|INFO|1C|http-nio-8080-exec-7|2022-03-21 22:37:28.238 UTC|AlpnExtension.java:182|No available application protocols
javax.net.ssl|DEBUG|1C|http-nio-8080-exec-7|2022-03-21 22:37:28.243 UTC|SSLExtensions.java:260|Ignore, context unavailable extension: application_layer_protocol_negotiation
javax.net.ssl|DEBUG|1C|http-nio-8080-exec-7|2022-03-21 22:37:28.243 UTC|SessionTicketExtension.java:408|Stateless resumption supported
javax.net.ssl|DEBUG|1C|http-nio-8080-exec-7|2022-03-21 22:37:28.244 UTC|SSLExtensions.java:260|Ignore, context unavailable extension: cookie
javax.net.ssl|DEBUG|1C|http-nio-8080-exec-7|2022-03-21 22:37:28.248 UTC|SSLExtensions.java:260|Ignore, context unavailable extension: renegotiation_info
javax.net.ssl|DEBUG|1C|http-nio-8080-exec-7|2022-03-21 22:37:28.248 UTC|PreSharedKeyExtension.java:662|No session to resume.
javax.net.ssl|DEBUG|1C|http-nio-8080-exec-7|2022-03-21 22:37:28.248 UTC|SSLExtensions.java:260|Ignore, context unavailable extension: pre_shared_key
javax.net.ssl|DEBUG|1C|http-nio-8080-exec-7|2022-03-21 22:37:28.250 UTC|ClientHello.java:652|Produced ClientHello handshake message (
"ClientHello": {
  "client version"      : "TLSv1.2",
  "random"              : "53 1B D2 D9 42 52 1C 8F E5 B0 E8 6A 88 0D A5 97 ED 22 83 1B CA C1 D4 26 1B 14 59 84 63 3C 99 5B",
  "session id"          : "4C 90 11 23 81 57 BD B5 AE 68 25 5F 32 E8 75 2B E2 8F A2 85 3A D7 76 4C F9 4C F7 16 5E 7C 02 B0",
  "cipher suites"       : "[TLS_AES_256_GCM_SHA384(0x1302), TLS_AES_128_GCM_SHA256(0x1301), TLS_CHACHA20_POLY1305_SHA256(0x1303), TLS_DHE_RSA_WITH_AES_256_GCM_SHA384(0x009F), TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256(0xCCAA), TLS_DH
E_DSS_WITH_AES_256_GCM_SHA384(0x00A3), TLS_DHE_RSA_WITH_AES_128_GCM_SHA256(0x009E), TLS_DHE_DSS_WITH_AES_128_GCM_SHA256(0x00A2), TLS_DHE_RSA_WITH_AES_256_CBC_SHA256(0x006B), TLS_DHE_DSS_WITH_AES_256_CBC_SHA256(0x006A), TLS_DHE_RSA_W
ITH_AES_128_CBC_SHA256(0x0067), TLS_DHE_DSS_WITH_AES_128_CBC_SHA256(0x0040), TLS_DHE_RSA_WITH_AES_256_CBC_SHA(0x0039), TLS_DHE_DSS_WITH_AES_256_CBC_SHA(0x0038), TLS_DHE_RSA_WITH_AES_128_CBC_SHA(0x0033), TLS_DHE_DSS_WITH_AES_128_CBC_
SHA(0x0032), TLS_RSA_WITH_AES_256_GCM_SHA384(0x009D), TLS_RSA_WITH_AES_128_GCM_SHA256(0x009C), TLS_RSA_WITH_AES_256_CBC_SHA256(0x003D), TLS_RSA_WITH_AES_128_CBC_SHA256(0x003C), TLS_RSA_WITH_AES_256_CBC_SHA(0x0035), TLS_RSA_WITH_AES_
128_CBC_SHA(0x002F), TLS_EMPTY_RENEGOTIATION_INFO_SCSV(0x00FF)]",
  "compression methods" : "00",
  "extensions"          : [
    "server_name (0)": {
      type=host_name (0), value=auth-service.mycompany.com
    },
    "status_request (5)": {
      "certificate status type": ocsp
      "OCSP status request": {
        "responder_id": <empty>
        "request extensions": {
          <empty>
        }
      }
    },
    "supported_groups (10)": {
      "versions": [ffdhe2048, ffdhe3072, ffdhe4096, ffdhe6144, ffdhe8192]
    },
    "ec_point_formats (11)": {
      "formats": [uncompressed]
    },
    "signature_algorithms (13)": {
      "signature schemes": [rsa_pss_rsae_sha256, rsa_pss_rsae_sha384, rsa_pss_rsae_sha512, rsa_pss_pss_sha256, rsa_pss_pss_sha384, rsa_pss_pss_sha512, rsa_pkcs1_sha256, rsa_pkcs1_sha384, rsa_pkcs1_sha512, dsa_sha256, rsa_sha224, dsa
_sha224, rsa_pkcs1_sha1, dsa_sha1]
    },
    "signature_algorithms_cert (50)": {
      "signature schemes": [rsa_pss_rsae_sha256, rsa_pss_rsae_sha384, rsa_pss_rsae_sha512, rsa_pss_pss_sha256, rsa_pss_pss_sha384, rsa_pss_pss_sha512, rsa_pkcs1_sha256, rsa_pkcs1_sha384, rsa_pkcs1_sha512, dsa_sha256, rsa_sha224, dsa
_sha224, rsa_pkcs1_sha1, dsa_sha1]
    },
    "status_request_v2 (17)": {
      "cert status request": {
        "certificate status type": ocsp_multi
        "OCSP status request": {
          "responder_id": <empty>
          "request extensions": {
            <empty>
          }
        }
      }
    },
    "extended_master_secret (23)": {
      <empty>
    },
    "session_ticket (35)": {
      <empty>
    },
    "supported_versions (43)": {
      "versions": [TLSv1.3, TLSv1.2]
    },
    "psk_key_exchange_modes (45)": {
      "ke_modes": [psk_dhe_ke]
    },
    "key_share (51)": {
      "client_shares": [
        {
          "named group": ffdhe2048
          "key_exchange": {
            0000: 8A B0 45 9E 04 62 D4 52   2F 35 E7 60 03 77 ED 8D  ..E..b.R/5.`.w..
            ...
          }
        },
      ]
    }
  ]
}
)
javax.net.ssl|DEBUG|1C|http-nio-8080-exec-7|2022-03-21 22:37:28.252 UTC|Alert.java:238|Received alert message (
"Alert": {
  "level"      : "fatal",
  "description": "handshake_failure"
}
)
javax.net.ssl|ERROR|1C|http-nio-8080-exec-7|2022-03-21 22:37:28.253 UTC|TransportContext.java:361|Fatal (HANDSHAKE_FAILURE): Received fatal alert: handshake_failure (
"throwable" : {
  javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure
        at java.base/sun.security.ssl.Alert.createSSLException(Alert.java:131)
...
)
javax.net.ssl|DEBUG|1C|http-nio-8080-exec-7|2022-03-21 22:37:28.253 UTC|SSLSocketImpl.java:1755|close the underlying socket
javax.net.ssl|DEBUG|1C|http-nio-8080-exec-7|2022-03-21 22:37:28.253 UTC|SSLSocketImpl.java:1774|close the SSL connection (initiative)
2022-03-21 22:37:28.255  WARN 26 --- [nio-8080-exec-7] o.keycloak.adapters.KeycloakDeployment   : Failed to load URLs from https://auth-service.mycompany.com/auth/realms/MyRealm/.well-known/openid-configuration

Если вы используете Java версии 8u261 или 11 и выше, уже недостаточно установить для этого sysprop значение ssl; вы должны добавить соответствующие «подтипы», такие как ssl:handshake:keymanager. Тем не менее, эта трассировка редко помогает при получении предупреждений о 40 проблемах, кроме отсутствия сертификата клиента — настроен ли ваш nginx на требование сертификата клиента? Что говорят журналы nginx?

dave_thompson_085 21.03.2022 23:25

Да, добавление ssl:handshake дало мне отладочный вывод, спасибо! Теперь... Пока не знаю, что с этим делать - я не вижу ни одного дымящегося пистолета. В журнале nginx нет ничего, кроме записей журнала доступа, но на самом деле я не вижу там запроса на .well-known/openid-configuration, поэтому похоже, что служба REST на самом деле не звонила? Или nginx не регистрирует запрос, потому что он не прошел во время рукопожатия.

DrTeeth 21.03.2022 23:50

вы можете взглянуть на этот вопрос SO, я думаю, что та же ошибка и может помочь stackoverflow.com/questions/6353849/…

tricksSpecialist 22.03.2022 00:05

Я просмотрел этот пост несколько раз, но не нашел ничего, что могло бы помочь. Сертификат подписан Digicert, который определенно находится в cacerts ОС и JDK и содержит как листовые, так и промежуточные сертификаты. Так что я не думаю, что это проблема с неполной цепочкой, хотя не уверен, как еще я бы сказал. Сервер nginx настроен на разрешение TLS 1.2 и 1.3, поэтому я думаю, что JDK должен иметь возможность согласовать один из этих двух. Домен точно правильный. Это оставило бы наборы шифров - я перепробовал все, что мог здесь придумать, но не уверен, как понять, что не так.

DrTeeth 22.03.2022 01:41

Накрутил логирование на nginx, получилось вот что: 2022/03/22 00:50:41 [info] 74#74: *22 SSL_do_handshake() failed (SSL: error:141F7065:SSL routines:final_key_share:no suitable key share) while SSL handshaking, client: #.#.#.#, server: 0.0.0.0:443

DrTeeth 22.03.2022 01:52

Я думаю, что основная проблема в том, что клиент отправляет список шифров: [TLS_AES_256_GCM_SHA384(0x1302), TLS_AES_128_GCM_SHA256(0x1301),... и сервер имеет свой список шифров: ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:..‌​. и они не пересекаются. Все клиентские шифры начинаются с TLS, а все серверные — с ECDHE. Я вытащил рекомендации сервера из списка рекомендаций по безопасности, поэтому не хочу их менять. Есть ли правильный способ добавить новые шифры в JDK?

DrTeeth 22.03.2022 02:12

Хорошо, я думаю, что это расходится с моим первоначальным вопросом, поэтому создаю здесь отдельный вопрос - stackoverflow.com/questions/71567383/…

DrTeeth 22.03.2022 06:40
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
0
7
76
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Синтаксис для включения отладки SSL, по-видимому, немного изменился. Это сработало для меня:

System.setProperty("javax.net.debug", "ssl:handshake");

Полная документация здесь.

Другие вопросы по теме