【问题标题】:SSLHandshakeException with jlink created runtimeSSLHandshakeException 与 jlink 创建运行时
【发布时间】:2019-08-21 16:52:43
【问题描述】:

我有一个 dropwizard 应用程序,它在标准 JRE 上运行良好。

我尝试过使用小得多的 jlink 创建运行时:

/Library/Java/JavaVirtualMachines/jdk-11.jdk/Contents/Home/bin/jlink --no-header-files --no-man-pages --compress=2 --strip-debug --add-modules java.base,java.compiler,java.desktop,java.instrument,java.logging,java.management,java.naming,java.scripting,java.security.jgss,java.sql,java.xml,jdk.attach,jdk.jdi,jdk.management,jdk.unsupported --output jre

如果我使用 jlink 创建的运行时运行它,它会在连接到 redis(前面有 stunnel)时抛出此错误。

ERROR [2019-03-31 09:12:20,080] com.company.project.core.WorkerThread: Failed to process message.
! javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure
! at java.base/sun.security.ssl.Alert.createSSLException(Unknown Source)
! at java.base/sun.security.ssl.Alert.createSSLException(Unknown Source)
! at java.base/sun.security.ssl.TransportContext.fatal(Unknown Source)
! at java.base/sun.security.ssl.Alert$AlertConsumer.consume(Unknown Source)
! at java.base/sun.security.ssl.TransportContext.dispatch(Unknown Source)
! at java.base/sun.security.ssl.SSLTransport.decode(Unknown Source)
! at java.base/sun.security.ssl.SSLSocketImpl.decode(Unknown Source)
! at java.base/sun.security.ssl.SSLSocketImpl.readHandshakeRecord(Unknown Source)
! at java.base/sun.security.ssl.SSLSocketImpl.startHandshake(Unknown Source)
! at java.base/sun.security.ssl.SSLSocketImpl.ensureNegotiated(Unknown Source)
! at java.base/sun.security.ssl.SSLSocketImpl$AppOutputStream.write(Unknown Source)
! at redis.clients.jedis.util.RedisOutputStream.flushBuffer(RedisOutputStream.java:52)
! at redis.clients.jedis.util.RedisOutputStream.flush(RedisOutputStream.java:133)
! at redis.clients.jedis.Connection.flush(Connection.java:300)
! ... 9 common frames omitted
! Causing: redis.clients.jedis.exceptions.JedisConnectionException: javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure
! at redis.clients.jedis.Connection.flush(Connection.java:303)
! at redis.clients.jedis.Connection.getStatusCodeReply(Connection.java:235)
! at redis.clients.jedis.BinaryJedis.auth(BinaryJedis.java:2225)
! at redis.clients.jedis.JedisFactory.makeObject(JedisFactory.java:119)
! at org.apache.commons.pool2.impl.GenericObjectPool.create(GenericObjectPool.java:888)
! at org.apache.commons.pool2.impl.GenericObjectPool.borrowObject(GenericObjectPool.java:432)
! at org.apache.commons.pool2.impl.GenericObjectPool.borrowObject(GenericObjectPool.java:361)
! at redis.clients.jedis.util.Pool.getResource(Pool.java:50)
! ... 2 common frames omitted
! Causing: redis.clients.jedis.exceptions.JedisConnectionException: Could not get a resource from the pool
! at redis.clients.jedis.util.Pool.getResource(Pool.java:59)
! at redis.clients.jedis.JedisPool.getResource(JedisPool.java:234)

stunnel 服务器日志显示:

redis_1  | 09:12:20 stunnel.1 | 2019.03.31 09:12:20 LOG7[23]: TLS alert (write): fatal: handshake failure
redis_1  | 09:12:20 stunnel.1 | 2019.03.31 09:12:20 LOG3[23]: SSL_accept: 141F7065: error:141F7065:SSL routines:final_key_share:no suitable key share
redis_1  | 09:12:20 stunnel.1 | 2019.03.31 09:12:20 LOG5[23]: Connection reset: 0 byte(s) sent to TLS, 0 byte(s) sent to socket

jlink 是否遗漏了一些加密算法?

【问题讨论】:

  • 嗯。如果我添加 jdk.crypto.ec 它可以工作 - 为什么 jdeps 会遗漏那个,如果那个,还会有其他遗漏吗?
  • 我似乎记得 JCA 提供者是扩展:库中没有任何东西直接依赖于它们,它们必须显式放入类路径中(就像其他典型的适配器扩展:数据库连接器等)

标签: java java-11 jlink


【解决方案1】:

正如comment 中的丰富提及

嗯。如果我添加 jdk.crypto.ec 它可以工作 - 为什么 jdeps 会遗漏那个,如果那个,还会有其他遗漏吗?

将 jdk.crypto.ec 添加到模块列表中解决了这个问题。

【讨论】:

  • 因此,您可以使用 HTTPS 支持链接一个非常好的运行时,但没有任何 SSL/TLS/... 实现,并且仅在握手失败并显示错误消息时才注意到...混淆。我明白为什么会发生这种情况,但这肯定不方便,也不遵循最小意外原则。
  • 这非常令人沮丧,这是修复。我在 JRE 上部署了几个月的应用程序,然后它突然失去了与我的服务器通信的能力(这意味着没有更新)。为什么他们不只包括这个。
  • 在 OpenJDK11.0.9/Win64 上,这会将 JRE 大小增加0.3 MiB
  • 请注意搜索引擎,它还修复了错误Received fatal alert: access_denied
【解决方案2】:

也可以在 jlink 命令中添加--bind-services(服务提供者模块及其依赖项中的链接)。但根据我的经验,这将使生成的运行时间更大。但至少这是一个快速找出观察到的问题是否是由于缺少服务实现的选项。

【讨论】:

    【解决方案3】:

    在 module-info.java 中添加了 requires jdk.crypto.ec; 为我解决了这个问题。

    【讨论】:

    • 这适用于我今天的用例。使用 GCP Java 客户端库时出现 DEADLINE_EXCEEDED 错误。这些发生在大约 10 秒后,所以我认为发生的事情是一些内部错误导致 gRPC 重试直到截止日期过去。不幸的是,10 秒后抛出的异常中的错误消息没有用。堆栈跟踪和原因以“异步任务错误”或其他内容结束。在调试时,我注意到 gRPC 抛出了一个与 SSL 相关的异常。将此模块添加到我的 jlink 运行时停止抛出此异常。
    【解决方案4】:

    我还必须添加jdk.crypto.ecjdk.crypto.cryptoki

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-05-15
      • 1970-01-01
      • 2012-05-05
      • 1970-01-01
      • 2019-04-13
      相关资源
      最近更新 更多