使用SSL保护Spring Boot应用程序

工程 | Scott Frederick | 2023年6月7日 | ...

安全套接字层 (SSL) 和传输层安全 (TLS) 是保护分层或面向服务的体系结构中系统之间通信的关键组件。这种体系结构中的 Spring Boot 应用程序通常接受传入的网络连接或创建传出连接,开发人员的任务是配置应用程序以在这样的安全环境中工作。

如果您曾经使用过 Java 安全和 SSL API,您可能知道这并不是一项特别有趣的任务。它通常需要多次访问stackoverflow.com 来复制和粘贴代码。有几个因素导致使用 SSL 变得痛苦。

首先,您可能会收到用于生产用途的证书和私钥等信任材料。您可能需要为生产前测试生成不同的信任材料(通常使用自签名证书颁发机构)。此信任材料通常以 JKS 或 PKCS #12 格式的 Java 密钥库文件的形式存在,或者它们可能是 PEM 编码的文本文件。每种文件类型都需要不同的处理方式。

获得信任材料后,您需要将其转换为可以传递给 Java 连接 API 的内容。事情可能会变得困难,因为连接 API 可以通过多种方式进行配置。

  • 有些需要您提供密钥库和信任库java.security.KeyStore 实例。
  • 有些需要您提供javax.net.ssl.KeyManagerjavax.net.ssl.TrustManager 实例。
  • 有些需要您提供javax.net.ssl.SSLContext 实例。

SSL 也是非常底层的,因此您通常需要剥离几层抽象才能到达需要使用java.securityjava.net.ssl 包中的对象进行配置的内容。例如,如果您想在 SpringRestTemplate 上配置 SSL,则需要深入到支持它的ClientHttpRequestFactory。对于典型的 Spring Boot 应用程序,这可能是HttpComponentsClientHttpRequestFactoryOkHttp3ClientHttpRequestFactorySimpleClientHttpRequestFactory。这些都提供了不同的配置 API。

为连接配置使用 SSL 或 TLS 对 Spring Boot 来说并不新鲜,但团队决定对当前支持的内容进行整体查看,并寻找改进和扩展支持的机会。我们希望您会发现 Spring Boot 3.1 使 SSL 配置变得更加容易。

介绍 SSL 包

Spring Boot 3.1 引入了 SSL 包的概念,用于配置和使用自定义 SSL 信任材料,例如密钥库、证书和私钥。配置后,可以使用配置属性或 API 将包应用于一个或多个连接。

配置 SSL 包

用于配置 SSL 信任材料的属性位于application.yamlapplication.properties 文件中的spring.ssl.bundle 前缀下。提供两个顶级分组以反映配置不同类型信任材料所需的唯一信息。

  • spring.ssl.bundle.jks 可用于使用 Java 密钥库文件配置包。
  • spring.ssl.bundle.pem 可用于使用 PEM 编码的文本文件配置包。

可以配置每种类型的一个或多个包,每个配置的包都由用户提供名称。在使用属性应用包或使用 API 检索包时,将使用此名称。

以下application.yaml 文件示例显示了两个 SSL 包的配置。第一个名为server,并定义了一个 Java 密钥库文件(PKCS #12 格式),可用于保护嵌入式 Web 服务器。第二个名为client,并定义了一个带有 PEM 编码证书文件的信任库,可用于保护与需要客户端身份验证的服务器的连接的客户端。

spring:
  ssl:
    bundle:
      jks:
        server:
          key:
            alias: "server"
          keystore:
            location: "classpath:server.p12"
            password: "secret"
            type: "PKCS12"
      pem:
        client:
          truststore:
            certificate: "classpath:client.crt"

请参阅Spring Boot 参考文档以及JksSslBundlePropertiesPemSslBundleProperties 类,以了解有关可用配置属性的更多详细信息。

使用自动配置的 SSL 包

Spring Boot 使用spring.ssl.bundle 属性创建提供对指定信任材料访问的对象。

如上所述,Java 安全和 SSL API 提供了三个抽象级别来公开从 Java 密钥库或 PEM 文件读取的信任材料。

  • 用作密钥库和信任库的java.security.KeyStore 实例。
  • javax.net.ssl.KeyManagerjavax.net.ssl.TrustManager 实例。
  • javax.net.ssl.SSLContext 实例。

在最低级别,您可能需要信任库和密钥库对象才能将 SSL 应用于连接。可以使用此处所示的SslStoreBundle 接口访问这些对象。

public interface SslStoreBundle {

	KeyStore getKeyStore();

	String getKeyStorePassword();

	KeyStore getTrustStore();

}

可以从密钥库和信任库派生KeyManagerTrustManager 实例。可以使用SslManagerBundle 接口访问这些实例。

public interface SslManagerBundle {

	KeyManager[] getKeyManagers();

	KeyManagerFactory getKeyManagerFactory();

	TrustManager[] getTrustManagers();

	TrustManagerFactory getTrustManagerFactory();

}

最后,可以从KeyManagerTrustManager 创建SSLContext,并使用createSslContext 工厂方法访问它。

将所有这些放在一起,我们得到了一个SslBundle 接口,它可以访问各种不同的配置样式。

public interface SslBundle {

	SslStoreBundle getStores();

	SslManagerBundle getManagers();

	SSLContext createSslContext() {

}

请参阅源代码,了解SslBundle 中所有方法的完整列表。

配置的SslBundle 集合在一个SslBundles bean 中可用,该 bean 可以自动连接到其他 Spring bean。

public interface SslBundles {

	SslBundle getBundle(String bundleName) throws NoSuchSslBundleException;

}

使用SslBundles 检索和应用SSLContext 的示例可能如下所示。

@Component
public class MyComponent {

    public MyComponent(SslBundles sslBundles) {
        SslBundle sslBundle = sslBundles.getBundle("client");
        SSLContext sslContext = sslBundle.createSslContext();
        // do something with the created sslContext
    }

}

保护 REST 客户端

Spring Boot 3.1 中启用的 SSL 功能的一个令人兴奋的新领域是 REST 客户端的配置。Spring Boot 对自定义RestTemplateWebClient 的支持现在包括将 SSL 包应用于保护客户端和 REST 服务之间的连接的能力。

RestTemplateBuilder 有一个新的setSslBundle() 方法,它接受从自动配置的SslBundles 检索的 SSL 包,如本例所示。

@Service
public class MyService {

    private final RestTemplate restTemplate;

    public MyService(RestTemplateBuilder restTemplateBuilder, SslBundles sslBundles) {
        this.restTemplate = restTemplateBuilder.setSslBundle(sslBundles.getBundle("mybundle")).build();
    }

}

WebClientSsl 接口允许检索 SSL 包并将其应用于WebClient.Builder,如本例所示。

@Service
public class MyService {

    private final WebClient webClient;

    public MyService(WebClient.Builder webClientBuilder, WebClientSsl ssl) {
        this.webClient = webClientBuilder.baseUrl("https://example.org").apply(ssl.fromBundle("mybundle")).build();
    }

}

保护数据服务连接

Spring Boot 使配置用于从应用程序连接到数据服务的客户端库变得容易。这些客户端库是使用所有三个级别的 Java 安全和 SSL API 进行配置的 API 的良好示例。

在 3.1 版本之前,Spring Boot 为许多提供自动配置的数据服务提供某种形式的 SSL 配置。但是,不同服务间的支持级别和配置属性并不一致。现在大多数数据服务的自动配置属性都具有类似的 ssl 结构,从而在不同服务之间提供了更高的一致性。

  • Cassandra - spring.cassandra.ssl
  • Couchbase - spring.couchbase.env.ssl
  • Elasticsearch - spring.elasticsearch.restclient.ssl
  • MongoDB - spring.data.mongodb.ssl
  • Redis - spring.data.redis.ssl

大多数服务都有一个 *.ssl.enabled 属性,它将使用 Java 运行时 cacerts 中包含的可信材料启用客户端库中的 SSL 支持。*.ssl.bundle 属性应用一个命名的 SSL 捆绑包,以使用来自捆绑包的自定义可信材料启用客户端库的 SSL 支持。这使得配置更加一致,并允许将相同的可信材料应用于多个连接,从而减少属性或 YAML 配置的数量。

为了提供这种一致性级别,一些以前的 SSL 相关属性已被弃用。有关更多详细信息,请参阅配置属性变更日志

JDBC 连接显然不在此列表中。我们计划在即将发布的 Spring Boot 版本中将 SSL 捆绑包方法应用于 JDBC 连接。

保护嵌入式 Web 服务器

Spring Boot 支持的所有嵌入式 Web 服务器都可以通过使用 server.ssl.* 属性配置为使用 SSL 保护传入连接。自 Spring Boot 推出以来就一直支持 Java 密钥库文件,自 2.7 版本以来一直支持 PEM 编码文件。

随着时间的推移,server.ssl 前缀下的属性数量不断增加,并且缺乏结构使得难以判断哪些属性可以一起使用,哪些属性是互斥的。之前的 server.ssl.* 属性仍然受支持,但是可以使用新的 server.ssl.bundle 属性将配置的 SSL 捆绑包应用于嵌入式 Web 服务器。

以下两个示例在功能上是相同的

server:
  ssl:
    key-alias: “server”
    key-password: “keysecret”
    key-store: "classpath:server.p12"
    key-store-password: "storesecret"
    client-auth: NEED    
spring:
  ssl:
    bundle:
      jks:
        web-server:
          key:
            alias: "server"
            password: “keysecret”
          keystore:
            location: "classpath:server.p12"
            password: "storesecret"
server:
  ssl:
    bundle: “web-server”
    client-auth: NEED

旧的结构更简洁,但新的结构减少了错误配置的可能性,并允许在多个连接上使用相同的 SSL 捆绑包。

management.server.sslspring.rsocket.server.ssl 属性也进行了类似的更改。

未来工作

我们真的希望您发现 SSL 捆绑包是 Spring Boot 3.1 的一个有用功能。如果您发现我们应该为其添加 SSL 支持的其他技术,请提出GitHub issue,我们会考虑将其纳入未来的版本。

获取 Spring 新闻通讯

与 Spring 新闻通讯保持联系

订阅

领先一步

VMware 提供培训和认证,以加速您的进步。

了解更多

获取支持

Tanzu Spring在一个简单的订阅中提供对OpenJDK™、Spring和Apache Tomcat®的支持和二进制文件。

了解更多

即将举行的活动

查看 Spring 社区中所有即将举行的活动。

查看全部