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

huangapple 未分类评论69阅读模式
标题翻译

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://java.coder-hub.com/60514176.html
匿名

发表评论

匿名网友

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

确定