知識庫 / Spring / Spring Boot RSS 訂閱

使用 SSL 捆綁安全 Spring Boot 應用

Spring Boot,Spring Security
HongKong
5
11:22 AM · Dec 06 ,2025

1. 引言

管理 Spring Boot 應用程序中的安全通信通常涉及處理複雜的配置。挑戰通常始於處理信任材料,例如證書和私鑰,這些材料以各種格式出現,如 JKS、PKCS #12 或 PEM。每種格式都有其自身的處理要求。

幸運的是,Spring Boot 3.1 引入了 SSL 捆綁包,這是一個旨在簡化這些複雜性的功能。在本教程中,我們將探索 SSL 捆綁包是什麼以及它們如何簡化 Spring Boot 應用程序的 SSL 配置任務。

2. Spring Boot SSL 捆包

通常,一旦我們獲取了信任材料,就需要將其轉換為應用程序可以使用的 Java 對象。 這通常意味着處理諸如 <em >java.security.KeyStore</em> 存儲密鑰材料、<em >javax.net.ssl.KeyManager</em> 用於管理這些密鑰材料以及 <em >javax.net.ssl.SSLContext</em> 用於創建安全套接字連接的類。

每個這些類都需要額外的理解和配置,使得過程既繁瑣又容易出錯。 各種 Spring Boot 組件也可能需要深入不同的抽象層才能應用這些設置,從而增加了任務的難度。

SSL 捆包封裝了所有信任材料和配置設置,例如密鑰存儲、證書和私鑰,到一個易於管理的單元中。 一旦配置了 SSL 捆包,就可以將其應用於一個或多個網絡連接,無論這些連接是入站還是出站。

SSL 捆包的配置屬性位於 <em >spring.ssl.bundle</em> 前綴的 <em >application.yaml</em><em >application.properties</em> 配置文件中。

讓我們從 JKS 捆包開始。 我們使用 spring.ssl.bundle.jks來配置使用 Java Keystore 文件的捆包:

spring:
  ssl:
    bundle:
      jks:
        server:
          key:
            alias: "server"
          keystore:
            location: "classpath:server.p12"
            password: "secret"
            type: "PKCS12"

對於 PEM 捆綁包,我們使用 spring.ssl.bundle.pem 用於使用 PEM 編碼的文本文件配置捆綁包:

spring:
  ssl:
    bundle:
      pem:
        client:
          truststore:
            certificate: "classpath:client.crt"

配置完成後,這些捆綁包可以應用於各個微服務——無論是需要安全訪問數據庫的庫存服務、需要安全 API 調用進行的身份驗證服務,還是與支付網關安全通信的支付處理服務。

**Spring Boot 自動化創建 Java 對象,如 KeyStoreKeyManagerSSLContext,基於 SSL 捆綁包配置。** 這消除了手動創建和管理這些對象的必要性,使流程更加簡單直接,並且降低了出錯的可能性。

3. 使用 SSL 捆綁包安全地使用 RestTemplate

讓我們從使用 SSL 捆綁包的同時安全地使用 RestTemplate 豆開始。為此,我們將使用一個示例 Spring Boot 應用程序,但首先,我們需要生成用於作為 SSL 捆綁包使用的密鑰。

我們將使用 openssl 二進制文件(通常與 git 一起安裝)來生成密鑰,通過在項目根目錄中執行以下命令:

$ openssl req -x509 -newkey rsa:4096 -keyout src/main/resources/key.pem -out src/main/resources/cert.pem -days 365 -passout pass:FooBar

現在,讓我們將此密鑰轉換為 PKCS12 格式:

$ openssl pkcs12 -export -in src/main/resources/cert.pem -inkey src/main/resources/key.pem -out src/main/resources/keystore.p12 -name secure-service -passin pass:FooBar -passout pass:FooBar

因此,我們擁有所有配置 SSL 捆綁包所需的資源;讓我們在 application.yml 文件中定義一個名為 “secure-service” 的捆綁包:

spring:
 ssl:
   bundle:
     jks:
       secure-service:
         key:
           alias: "secure-service"
         keystore:
           location: "classpath:keystore.p12"
           password: "FooBar"
           type: "PKCS12"

接下來,我們可以通過調用 setSslBundle() 方法來將 bundle 設置到 RestTemplate 上:

@Bean
public RestTemplate restTemplate(RestTemplateBuilder restTemplateBuilder, SslBundles sslBundles) {
    return restTemplateBuilder.setSslBundle(sslBundles.getBundle("secure-service")).build();
}

最後,我們可以使用配置好的 RestTemplate Bean 調用一個 API:

@Service
public class SecureServiceRestApi {
    private final RestTemplate restTemplate;

    @Autowired
    public SecureServiceRestApi(RestTemplate restTemplate) {
        this.restTemplate = restTemplate;
    }

    public String fetchData(String dataId) {
        ResponseEntity<String> response = restTemplate.exchange(
          "https://secure-service.com/api/data/{id}",
          HttpMethod.GET,
          null,
          String.class,
          dataId
        );
        return response.getBody();
    }
}

在我們的 Spring Boot 應用程序中,SSL Bundle 的作用是驗證 secure-service 的證書,從而確保建立加密且安全的通信通道。 但這並不能阻止我們使用客户端證書進行 API 端的身份驗證。稍後我們將看到如何獲取 SSLContext 以配置自定義客户端。

4. 利用 Spring Boot 的自動配置的 SSLBundles

在 Spring Boot 的 SSL Bundles 出現之前,開發者們通常使用經典的 Java 類來構建 SSL 配置:

  • java.security.KeyStore:這些實例用作密鑰庫和信任庫,有效地充當了加密密鑰和證書的安全存儲庫。
  • javax.net.ssl.KeyManagerjavax.net.ssl.TrustManager:這些實例分別管理 SSL 通信期間的密鑰和信任決策。
  • javax.net.ssl.SSLContext:這些實例充當 SSLEngineSSLSocket 對象的工廠,在運行時協調 SSL 配置的實施。

Spring Boot 3.1 引入了結構化的抽象層,分為 Java 接口:

  • SslStoreBundle:提供訪問 KeyStore 對象的途徑,其中包含加密密鑰和受信任的證書。
  • SslManagerBundle:協調並提供管理 KeyManagerTrustManager 對象的便捷方法。
  • SslBundle:作為一站式解決方案,將所有這些功能聚合到一個統一的與 SSL 生態系統交互的模型中。

隨後,Spring Boot 會自動配置一個 SslBundles Bean。 結果是,我們可以方便地將 SslBundle 實例注入到任何 Spring Bean 中。 這對於配置遺留代碼庫和自定義 REST 客户端的安全性尤其有用。

例如,讓我們考慮為自定義安全的 HttpClient 創建一個自定義 SSLContext 的情況:

@Component
public class SecureRestTemplateConfig {
    private final SSLContext sslContext;

    @Autowired
    public SecureRestTemplateConfig(SslBundles sslBundles) throws NoSuchSslBundleException {
        SslBundle sslBundle = sslBundles.getBundle("secure-service");
        this.sslContext = sslBundle.createSslContext();
    }

    @Bean
    public RestTemplate secureRestTemplate() {
        SSLConnectionSocketFactory sslSocketFactory = SSLConnectionSocketFactoryBuilder.create().setSslContext(this.sslContext).build();
        HttpClientConnectionManager cm = PoolingHttpClientConnectionManagerBuilder.create().setSSLSocketFactory(sslSocketFactory).build();
        HttpClient httpClient = HttpClients.custom().setConnectionManager(cm).evictExpiredConnections().build();
        HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory(httpClient);
        return new RestTemplate(factory);
    }
}

在上述代碼中,我們注入了 SslBundles 實例到 Autowired 構造函數中。實際上,SslBundles 提供了我們訪問所有配置的 SSL Bundles 的途徑。因此,我們檢索 secure-service bundle 並創建上下文。稍後,我們使用 SSLContext 實例來創建自定義的 HttpClient 並將其應用於創建 RestTemplate bean。

<h2>5. 使用 SSL 捆綁包與數據服務</h2>
<p>不同的數據服務具有不同的 SSL 配置選項,這在配置過程中會帶來複雜性。</p>
<p><strong>SSL 捆綁包引入了一種更統一的 SSL 配置方法,適用於廣泛的數據服務:</strong></p>
<ul>
 <li>Cassandra: <em>spring.cassandra.ssl</em></li>
 <li>Couchbase: <em>spring.couchbase.env.ssl</em></li>
 <li>Elasticsearch: <em>spring.elasticsearch.restclient.ssl</em></li>
 <li>MongoDB: <em>spring.data.mongodb.ssl</em></li>
 <li>Redis: <em>spring.data.redis.ssl</em></li>
</ul>
<p>現在,<strong>大多數服務都支持 <em>*.ssl.enabled</em> 屬性。此屬性激活客户端庫中的 SSL 支持,並利用 Java 運行時環境中的 <em>cacerts</em> 中的信任材料。</strong></p>
<p>此外,<em>*.ssl.bundle</em> 屬性允許我們應用一個命名的 SSL 捆綁包,以自定義信任材料,從而實現跨多個服務連接的統一性和可重用性。</p>
<p>為了本示例,假設有一個名為 <em>mongodb-ssl-bundle</em> 的 SSL 捆綁包。此捆綁包包含用於安全連接到 MongoDB 實例的必要信任材料。</p>
<p>讓我們定義 <em>application.yml</em> 文件:</p>
spring:
  data:
    mongodb:
      ssl:
        enabled: true
        bundle: mongodb-ssl-bundle

只需添加這些屬性,Spring Boot應用程序中的 MongoDB 客户端庫將自動使用 mongodb-ssl-bundle 中指定的 SSL 上下文和信任材料。

6. 使用包含嵌入式服務器的 SSL 包

使用 SSL 包可以簡化 Spring Boot 中嵌入式 Web 服務器的 SSL 配置管理。

傳統上,<em >server.ssl.*</em> 屬性用於設置每個單獨的 SSL 配置。 使用 SSL 包,可以將配置分組並可重用在多個連接中,從而減少錯誤的可能性並簡化整體管理

首先,讓我們探討傳統的單個屬性方法:

server:
  ssl:
    key-alias: "server"
    key-password: "keysecret"
    key-store: "classpath:server.p12"
    key-store-password: "storesecret"
    client-auth: NEED

另一方面,SSL Bundle 方法允許將相同的配置封裝在一起:

spring:
  ssl:
    bundle:
      jks:
        web-server:
          key:
            alias: "server"
            password: "keysecret"
          keystore:
            location: "classpath:server.p12"
            password: "storesecret"

現在,我們可以使用定義的包來安全我們的 Web 服務器。

server:
  ssl:
    bundle: "web-server"
    client-auth: NEED

雖然兩種方法都可確保嵌入式 Web 服務器的安全,但 SSL Bundle 方法在配置管理方面更高效。此功能也適用於其他配置,例如 management.server.sslspring.rsocket.server.ssl

7. 結論

在本文中,我們探討了 Spring Boot 中的新 SSL 捆綁包功能,該功能可以簡化並統一配置信任材料的過程。

與傳統的 <em >server.ssl.*</em> 屬性相比,SSL 捆綁包提供了一種結構化的方式來管理密鑰存儲庫(keystores)和信任存儲庫(truststores)。 這種方法尤其有益於降低配置錯誤風險並提高跨多服務範圍內的 SSL 管理效率。

此外,SSL 捆綁包非常適合集中管理,允許相同的捆綁包在應用程序的不同部分重複使用。

通過採用 SSL 捆綁包,開發人員不僅可以簡化配置過程,還可以提升 Spring Boot 應用程序中嵌入式 Web 服務器的安全性。

user avatar
0 位用戶收藏了這個故事!
收藏

發佈 評論

Some HTML is okay.