Spring Boot支持服务器名称指示(SNI)吗?

huangapple go评论76阅读模式
英文:

Does Spring Boot support Server Name Indication (SNI)?

问题

Spring Boot支持服务器名称指示(SNI)吗?具体地说,一个运行在嵌入式Tomcat服务器上并打包为可执行jar文件的Spring Boot应用,是否可以根据传入请求的主机名支持多个基于SSL证书/域名的配置?

看起来[Tomcat支持SNI](https://dzone.com/articles/sni-in-tomcat "SNI in Tomcat")(从Tomcat 8.5开始),但我不太清楚如何在我的Spring Boot应用中实现SNI。

英文:

Does Spring Boot support Server Name Indication (SNI)? Specifically, is it possible for a Spring Boot (2.2.2.RELEASE) application running an embedded Tomcat server and packaged as an executable jar file to support multiple SSL certificates/domains based on the hostname of the incoming request?

It appears [Tomcat supports SNI](https://dzone.com/articles/sni-in-tomcat "SNI in Tomcat") (as of Tomcat 8.5), but I'm not sure how to implement SNI in my Spring Boot app.

答案1

得分: 6

我能够验证 Spring Boot 运行嵌入式 Tomcat 服务器支持使用以下配置的服务器名称指示(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);
        }
    }

}
英文:

I was able to verify that Spring Boot running an embedded Tomcat server supports Server Name Indication (SNI) using the following config:

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(&quot;org.apache.coyote.http11.Http11NioProtocol&quot;);
/**
* Tomcat 9.0.x server SSL Connector for multiple hosts
* 
&lt;Connector port=&quot;8443&quot; protocol=&quot;org.apache.coyote.http11.Http11NioProtocol&quot;
maxThreads=&quot;150&quot; SSLEnabled=&quot;true&quot;
defaultSSLHostConfigName=&quot;*.abc.com&quot;&gt;
&lt;SSLHostConfig hostName=&quot;*.abc.com&quot;&gt;
&lt;Certificate certificateKeystoreFile=&quot;conf/abc.com.p12&quot;
type=&quot;RSA&quot; /&gt;
&lt;/SSLHostConfig&gt;
&lt;SSLHostConfig hostName=&quot;*.xyz.com&quot;&gt;
&lt;Certificate certificateKeystoreFile=&quot;conf/xyz.com.p12&quot;
type=&quot;RSA&quot; /&gt;
&lt;/SSLHostConfig&gt;
&lt;/Connector&gt;
*/
try {
connector.setScheme(&quot;https&quot;);
connector.setSecure(true);
connector.setPort(8443);
connector.setAttribute(&quot;SSLEnabled&quot;, &quot;true&quot;);
connector.setAttribute(&quot;defaultSSLHostConfigName&quot;, &quot;*.abc.com&quot;);
// *.abc.com
SSLHostConfig sslHostConfig = new SSLHostConfig();
sslHostConfig.setHostName(&quot;*.abc.com&quot;);
SSLHostConfigCertificate sslHostConfigCertificate = new SSLHostConfigCertificate(sslHostConfig, Type.RSA);
sslHostConfigCertificate.setCertificateKeystoreFile(env.getProperty(&quot;abc.com.key-store&quot;));
sslHostConfig.addCertificate(sslHostConfigCertificate);
connector.addSslHostConfig(sslHostConfig);
// *.xyz.com
sslHostConfig = new SSLHostConfig();
sslHostConfig.setHostName(&quot;*.xyz.com&quot;);
sslHostConfigCertificate = new SSLHostConfigCertificate(sslHostConfig, Type.RSA);
sslHostConfigCertificate.setCertificateKeystoreFile(env.getProperty(&quot;xyz.com.key-store&quot;));
sslHostConfig.addCertificate(sslHostConfigCertificate);
connector.addSslHostConfig(sslHostConfig);
return connector;
}
catch (Exception ex) {
throw new IllegalStateException(&quot;Exception creating SSL Connector: &quot;, ex);
}
}
}

答案2

得分: 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 supports tomcat connector configuration. I did not run this code but this will give you some idea. You can try something like this:

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

huangapple
  • 本文由 发表于 2020年3月4日 03:22:24
  • 转载请务必保留本文链接:https://go.coder-hub.com/60514176.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定