javax.net.ssl.SSLHandshakeException:没有适当的协议。如何强制Java使用TLSv1.2发送邮件?

2024-02-28

我正在尝试使用 JavaMailSender 在 Spring Boot 中发送邮件,但出现此错误:

javax.net.ssl.SSLHandshakeException: No appropriate protocol (protocol is disabled or cipher suites are inappropriate). Failed messages: javax.mail.MessagingException: Could not convert socket to TLS;
  nested exception is:
    javax.net.ssl.SSLHandshakeException: No appropriate protocol (protocol is disabled or cipher suites are inappropriate)

经过一些阅读后,我发现这是因为我们使用的是过时的 TLSv1 或 TLSv1.1,我们应该使用 v1.2 或更高版本。我尝试在 application.yml 中添加值为 TLSv1.2 的 ssl.protocols 属性,但它似乎不起作用。这是我的 application.yml:

spring:
  mail:
    host: smtp.gmail.com
    port: 587
    username: ******@gmail.com
    password: *******
    protocol: smtp
    tls: true
    properties.mail.smtp:
      auth: true
      ssl.trust: smtp.gmail.com
      starttls.required: true
      starttls.enabled: true
      ssl.protocols: TLSv1.2

这是发送邮件的方法:

public void sendEmail(String to, String subject, String body) {
    logger.info("Sending mail to : " + to);
    SimpleMailMessage mail = new SimpleMailMessage();
    mail.setTo(to);
    mail.setSubject(subject);
    mail.setText(body);

    try {
        javaMailSender.send(mail);
        logger.info("Mail sent to " + to);
    } catch (Exception e) {
        logger.error("Could not send mail to " + to + ". Exception : " + e.getMessage());
    }
}

我更新了 JavaMailSender 版本,但没有解决问题。唯一有效的方法是从 jdk.tls.disabledAlgorithms 中删除 TLSv1 和 TLSv1.1,如这个答案 https://stackoverflow.com/a/68238768/8198017,但这只是临时修复。如何让邮件发件人使用 TLSv1.2 或更高版本?我在 application.yml 中定义 ssl.protocols 属性的方式有什么问题吗?

这是我正在使用的java版本:

openjdk version "1.8.0_292"
OpenJDK Runtime Environment (AdoptOpenJDK)(build 1.8.0_292-b10)
OpenJDK 64-Bit Server VM (AdoptOpenJDK)(build 25.292-b10, mixed mode)

和 Spring Boot Starter 邮件版本:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-mail</artifactId>
    <version>2.5.3</version>
</dependency>

我最近回答了一个几乎相同的问题question https://stackoverflow.com/questions/68591048/javax-could-not-convert-socket-to-tls/68773865#68773865.

正如您所猜测的,您的问题将与a change https://www.oracle.com/java/technologies/javase/11-0-11-relnotes.html#JDK-8202343在 JDK 中引入,以默认禁用不安全的 TLS 协议版本:

安全库/javax.net.ssl
禁用 TLS 1.0 和 1.1

TLS 1.0 和 1.1 是 TLS 协议的版本,不再适用 被认为是安全的,并已被更安全和现代的产品所取代 版本(TLS 1.2 和 1.3)。

这些版本现在已默认禁用。如果你遇到 问题,您可以通过删除来重新启用版本,风险自负 “TLSv1”和/或“TLSv1.1”来自jdk.tls.disabledAlgorithms的安全财产java.security配置文件。

正如你在错误描述 https://bugs.openjdk.java.net/browse/JDK-8202343,这一更改已向后移植到不同的 JDK 版本,即您正在使用的版本。

为了解决该问题,您可以编辑您的java.security配置文件并删除TLSv1 and/or TLSv1.1来自jdk.tls.disabledAlgorithms安全财产。

此外,您可以在配置属性中显式包含所需的 TLS 协议:

props.put("mail.smtp.ssl.protocols", "TLSv1.2");

老实说,我不明白为什么 Spring Boot 没有应用这个配置,看来你定义它是正确的。您可以在描述时查看库的源代码来检查它邮件属性配置 https://github.com/spring-projects/spring-boot/blob/47516b50c39bd6ea924a1f6720ce6d4a71088651/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/mail/MailSenderPropertiesConfiguration.java和不同的接受的邮件属性 https://github.com/spring-projects/spring-boot/blob/47516b50c39bd6ea924a1f6720ce6d4a71088651/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/mail/MailProperties.java,并且如中所述Spring Boot 文档 https://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#application-properties.mail以及。请尝试像这样定义属性:

spring:
  mail:
    properties:
      # other properties you need
      "mail.smtp.ssl.protocols": "TLSv1.2"

为了放弃一些可能与 YAML 格式相关的问题,您可以尝试显式设置此属性,仅用于测试,在JavaMaiSenderImpl https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/mail/javamail/JavaMailSenderImpl.html:

public void sendEmail(String to, String subject, String body) {
    logger.info("Sending mail to : " + to);
    SimpleMailMessage mail = new SimpleMailMessage();
    mail.setTo(to);
    mail.setSubject(subject);
    mail.setText(body);

    try {
        // Just for validating the solution
        JavaMailSenderImpl javaMailSenderImpl = (JavaMailSenderImpl)javaMailSender;
        // Please, put a breakpoint here and debug the configured
        // properties, it will provide you a valuable information
        // about the actual properties that have been applied      
javaMailSenderImpl.getJavaMailProperties().put("mail.smtp.ssl.protocols", "TLSv1.2");

        javaMailSender.send(mail);
        logger.info("Mail sent to " + to);
    } catch (Exception e) {
        logger.error("Could not send mail to " + to + ". Exception : " + e.getMessage());
    }
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

javax.net.ssl.SSLHandshakeException:没有适当的协议。如何强制Java使用TLSv1.2发送邮件? 的相关文章

随机推荐