英文:
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("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
得分: 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("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;
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论