【问题标题】:How to force Spring boot embedded tomcat to use SNI (Server Name Indication)如何强制 Spring Boot 嵌入式 tomcat 使用 SNI(服务器名称指示)
【发布时间】:2022-01-13 15:09:26
【问题描述】:

我需要确保我的客户端支持 SNI 并且可以正常工作。为此,我想启动一些需要来自客户端的主机名的虚拟服务器(带有嵌入式 Tomcat 9 的 Spring Boot 应用程序)。问题是如何强制 Spring Boot 嵌入式 Tomcat 要求来自客户端的 SNI? 我已经读过要做到这一点,我们需要向服务器提供 2 个(或更多)证书。

我试图从这个topic 中学习示例。但这对我不起作用。

我生成了 2 个密钥库 mycompany1.keystoremycompany2.keystore,每个密钥库都有 1 个证书。还有 1 个信任库 mycompany.truststore 存储这两个证书。证书有CNmy.hostname.commy.another.hostname.com

这是我配置嵌入式 tomcat 的方式:

@Component
public class MultipleHostsTomcatFactory {

    @Value("${abc.com.key-store}")
    String abcComKeyStore;

    @Value("${xyz.com.key-store}")
    String xyzComKeyStore;

    @Value("${server.port}")
    int serverPort;

    @Value("${server.http.port:8080}")
    private int httpPort;

    @Bean
    public ServletWebServerFactory servletContainer() throws Exception {
        TomcatServletWebServerFactory factor = new TomcatServletWebServerFactory();
        factor.addAdditionalTomcatConnectors(createSSLConnectorForMultipleHosts());
        return factor;
    }

    private Connector createSSLConnectorForMultipleHosts() {
        Connector connector = null;
        try {
            connector = new Connector("org.apache.coyote.http11.Http11NioProtocol");
            connector.setScheme("https");
            connector.setSecure(true);
            connector.setProperty("SSLEnabled", "true");
            connector.setProperty("defaultSSLHostConfigName", /*"*.abc.com"*/ "*.hostname.com");
            connector.setPort(8444);

            // *.abc.com
            SSLHostConfig sslHostConfig = new SSLHostConfig();
            sslHostConfig.setHostName("*.abc.com");

            SSLHostConfigCertificate sslHostConfigCertificate = new SSLHostConfigCertificate(sslHostConfig, SSLHostConfigCertificate.Type.EC);
            sslHostConfigCertificate.setCertificateKeystoreFile(abcComKeyStore);

            sslHostConfig.addCertificate(sslHostConfigCertificate);
            connector.addSslHostConfig(sslHostConfig);

            // *.xyz.com
            sslHostConfig = new SSLHostConfig();
            sslHostConfig.setHostName("*.xyz.com");

            sslHostConfigCertificate = new SSLHostConfigCertificate(sslHostConfig, SSLHostConfigCertificate.Type.EC);
            sslHostConfigCertificate.setCertificateKeystoreFile(xyzComKeyStore);

            sslHostConfig.addCertificate(sslHostConfigCertificate);
            connector.addSslHostConfig(sslHostConfig);
        } catch (Exception e) {
            System.out.println("Catched exception!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
            e.printStackTrace();
        }
        return connector;
    }
}

此代码基于此topic。 但我有一个错误:

2022-01-13 16:10:21.301 ERROR 22364 --- [           main] org.apache.catalina.util.LifecycleBase   : Failed to initialize component [Connector[HTTP/1.1-8444]]

org.apache.catalina.LifecycleException: Protocol handler initialization failed
...
Caused by: java.lang.IllegalArgumentException: Keystore was tampered with, or password was incorrect
...
Caused by: java.io.IOException: Keystore was tampered with, or password was incorrect
...
Caused by: java.security.UnrecoverableKeyException: Password verification failed

我好像错过了什么。

那么,如何强制嵌入式 Tomcat 启用 SNI?

【问题讨论】:

  • 请尝试将abc.comxyz.com 替换为my.host... 始终(而不是混合;)
  • @xerx593,我将它们替换为my.hostname.commy.another.hostname.com。没有帮助。
  • 那么 defaultSSLHostConfigName 呢?
  • @xerx593,更改为 my.hostname.commy.another.hostname.com(两种变体都试过) - 没有帮助。关于这个错误的问题是:spring 验证什么?我没有配置任何密码。
  • 您对这些密钥库使用了什么格式?尝试使用setCertificateKeystoreType 设置正确的。

标签: java spring-boot tomcat sni


【解决方案1】:

我解决了这个问题。也许我的解释会对某人有所帮助。我只是按照我看到的错误配置了服务器遗漏的所有数据。我没有配置证书,因为我有存储此证书的密钥库。我的最终服务器有 2 个仅支持 TLSv1.3 的主机(满足我的需要):

private Connector createSSLConnectorForMultipleHosts() {
    Connector connector = null;
    try {
        Http2Protocol http2Protocol = new Http2Protocol();
        Http11NioProtocol http11Protocol = new Http11NioProtocol();
        http2Protocol.setHttp11Protocol(http11Protocol);

        connector = new Connector(http11Protocol);
        connector.addUpgradeProtocol(http2Protocol);
        connector.setScheme("https");
        connector.setSecure(true);
        connector.setProperty("SSLEnabled", "true");
        connector.setProperty("defaultSSLHostConfigName", "my.hostname.com");
        connector.setPort(8445);

        // first
        SSLHostConfig sslHostConfig = new SSLHostConfig();
        sslHostConfig.setHostName("my.hostname.com");
        sslHostConfig.setCertificateKeystorePassword("mypassword");
        sslHostConfig.setCertificateKeystoreFile(firstKeyStore);
        sslHostConfig.setProtocols("TLSv1.3");
        connector.addSslHostConfig(sslHostConfig);

        // second
        sslHostConfig = new SSLHostConfig();
        sslHostConfig.setHostName("my.another.hostname.com");
        sslHostConfig.setCertificateKeystorePassword("mypassword");
        sslHostConfig.setCertificateKeystoreFile(secondKeyStore);
        sslHostConfig.setProtocols("TLSv1.3");
        connector.addSslHostConfig(sslHostConfig);
    } catch (Exception e) {
        e.printStackTrace();
    }
    return connector;
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-07-04
    • 2017-05-23
    • 2020-05-08
    • 2012-09-03
    • 2019-10-11
    • 1970-01-01
    • 2012-10-08
    相关资源
    最近更新 更多