如何获取Java SSL握手的调试信息?

3
我正在尝试使用Keycloak来保护Java Spring Boot REST服务。其中一部分涉及服务与Keycloak之间的通信,以获取公认的OpenID配置。
当所有内容未加密(通过HTTP)时,一切都正常。但是,当我将SSL证书引入混合中(技术上位于两个服务前面的nginx服务器上),就会出现SSL握手错误。
如果我直接使用浏览器访问REST服务或Keycloak,浏览器不会报告SSL错误。从REST服务器机器到Keycloak机器上使用curl也看起来很好,我曾尝试让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
  • 在应用程序的main()函数中添加System.setProperty("javax.net.debug", "ssl");
  • logging.level.javax=TRACElogging.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

2
如果您正在使用Java版本8u261或11及以上版本,则仅设置sysprop为ssl已不足,您必须添加相关的“子类型”,例如ssl:handshake:keymanager。然而,这种跟踪很少有助于解决除缺少客户端证书之外的警报接收40问题 - 您的nginx是否设置为需要客户端证书?Nginx日志显示了什么? - dave_thompson_085
是的 - 添加ssl:handshake让我得到了调试输出,谢谢!现在...还不确定该怎么做 - 我没有看到任何明显的问题。nginx日志除了访问日志条目之外没有其他内容 - 但我实际上没有在那里看到.well-known/openid-configuration的请求,所以看起来REST服务实际上没有发出调用?或者nginx在握手期间失败时不记录请求。 - DrTeeth
你可以看一下这个 Stack Overflow 的问题,我认为它和你遇到的错误相同,可能会有所帮助:https://dev59.com/M2w15IYBdhLWcg3w3fjN - tricksSpecialist
1
我认为主要问题在于客户端发送了一系列密码:[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
好的,我认为这已经偏离了我的初始问题,因此在这里创建一个单独的问题 - https://dev59.com/6Lb3oIgBc1ULPQZF3kGx - DrTeeth
显示剩余2条评论
1个回答

11

启用 SSL 调试的语法似乎有些变化。这对我有效:

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

完整文档在此处


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接