【问题标题】:Does Spring Boot support Server Name Indication (SNI)?Spring Boot 是否支持服务器名称指示(SNI)?
【发布时间】:2020-03-03 19:22:24
【问题描述】:

Spring Boot 是否支持服务器名称指示 (SNI)?具体来说,运行嵌入式 Tomcat 服务器并打包为可执行 jar 文件的 Spring Boot (2.2.2.RELEASE) 应用程序是否可以根据传入请求的主机名支持多个 SSL 证书/域?

它显示为Tomcat supports SNI(从 Tomcat 8.5 开始),但我不确定如何在我的 Spring Boot 应用程序中实现 SNI。

【问题讨论】:

    标签: java spring-boot ssl sni


    【解决方案1】:

    我能够使用以下配置验证运行嵌入式 Tomcat 服务器的 Spring Boot 是否支持服务器名称指示 (SNI):

    application.properties

    abc.com.key-store=${user.dir}/abc.com.p12
    xyz.com.key-store=${user.dir}/xyz.com.p12
    

    ApplicationConfig.java

    import org.apache.catalina.connector.Connector;
    import org.apache.tomcat.util.net.SSLHostConfig;
    import org.apache.tomcat.util.net.SSLHostConfigCertificate;
    import org.apache.tomcat.util.net.SSLHostConfigCertificate.Type;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
    import org.springframework.boot.web.servlet.server.ServletWebServerFactory;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.core.env.Environment;
    
    @Configuration
    public class ApplicationConfig {
    
        @Autowired
        private Environment env;
    
        @Bean
        public ServletWebServerFactory servletContainer() throws Exception {
    
            TomcatServletWebServerFactory tomcat = new TomcatServletWebServerFactory() {
                // Override TomcatServletWebServerFactory methods (if needed)
            };
    
            // add SSL Connector
            tomcat.addAdditionalTomcatConnectors(createSSLConnectorForMultipleHosts());
    
            return tomcat;
        }
    
    
        private Connector createSSLConnectorForMultipleHosts() {
            Connector connector = new Connector("org.apache.coyote.http11.Http11NioProtocol");
    
            /**
             * Tomcat 9.0.x server SSL Connector for multiple hosts
             * 
            <Connector port="8443" protocol="org.apache.coyote.http11.Http11NioProtocol"
                       maxThreads="150" SSLEnabled="true"
                       defaultSSLHostConfigName="*.abc.com">
                <SSLHostConfig hostName="*.abc.com">
                    <Certificate certificateKeystoreFile="conf/abc.com.p12"
                                 type="RSA" />
                </SSLHostConfig>
                <SSLHostConfig hostName="*.xyz.com">
                    <Certificate certificateKeystoreFile="conf/xyz.com.p12"
                                 type="RSA" />
                </SSLHostConfig>
            </Connector>
             */
    
            try {
                connector.setScheme("https");
                connector.setSecure(true);
                connector.setPort(8443);
                connector.setAttribute("SSLEnabled", "true");
                connector.setAttribute("defaultSSLHostConfigName", "*.abc.com");
    
                // *.abc.com
                SSLHostConfig sslHostConfig = new SSLHostConfig();
                sslHostConfig.setHostName("*.abc.com");
    
                SSLHostConfigCertificate sslHostConfigCertificate = new SSLHostConfigCertificate(sslHostConfig, Type.RSA);
                sslHostConfigCertificate.setCertificateKeystoreFile(env.getProperty("abc.com.key-store"));
    
                sslHostConfig.addCertificate(sslHostConfigCertificate);
                connector.addSslHostConfig(sslHostConfig);
    
                // *.xyz.com
                sslHostConfig = new SSLHostConfig();
                sslHostConfig.setHostName("*.xyz.com");
    
                sslHostConfigCertificate = new SSLHostConfigCertificate(sslHostConfig, Type.RSA);
                sslHostConfigCertificate.setCertificateKeystoreFile(env.getProperty("xyz.com.key-store"));
    
                sslHostConfig.addCertificate(sslHostConfigCertificate);
                connector.addSslHostConfig(sslHostConfig);
    
                return connector;
            }
            catch (Exception ex) {
                throw new IllegalStateException("Exception creating SSL Connector: ", ex);
            }
        }
    
    }
    

    【讨论】:

      【解决方案2】:

      Spring 支持 tomcat 连接器配置。我没有运行这段代码,但这会给你一些想法。你可以试试这样:

      @Bean
      public ServletWebServerFactory servletContainer() throws Exception {
          TomcatServletWebServerFactory tomcat = new TomcatServletWebServerFactory();
          tomcat.addAdditionalTomcatConnectors(createConnector());
          return tomcat;
      }
      
      public Connector createConnector() {
          Connector connector = new Connector("org.apache.coyote.http11.Http11AprProtocol");
          connector.setScheme("https");
          connector.setSecure(true);
          connector.setPort(8443);
          connector.addSslHostConfig(getSSLHostConfig());
          return connector;
      }
      
      private SSLHostConfig getSSLHostConfig() {
          SSLHostConfig sslHostConfig = new SSLHostConfig();
          sslHostConfig.setHostName("abc.com");
          sslHostConfig.setCertificateFile("abc.crt");
          sslHostConfig.setCaCertificateFile("xyz.crt");
          return sslHostConfig;
      }
      

      【讨论】:

      • 感谢有用的代码提示,因为它让我能够验证 Spring Boot 确实支持服务器名称指示 (SNI)。
      猜你喜欢
      • 1970-01-01
      • 2011-12-19
      • 1970-01-01
      • 2022-12-11
      • 2012-07-26
      • 2017-05-23
      • 1970-01-01
      • 1970-01-01
      • 2012-09-03
      相关资源
      最近更新 更多