使用 SSL 保護 Spring Boot 應用程式

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

安全通訊端層 (SSL) 和傳輸層安全性 (TLS) 是確保分層或面向服務架構中系統之間通訊的關鍵組件。 這種架構中的 Spring Boot 應用程式通常會接受傳入的網路連線或建立傳出的連線,而開發人員的任務是設定應用程式以在這種安全的環境中運作。

如果您曾經使用過 Java 安全性與 SSL API,您可能知道這不是一項特別有趣的任務。 它通常需要多次造訪 stackoverflow.com 來複製和貼上程式碼。 有幾個因素使得使用 SSL 令人痛苦。

首先,您可能會獲得用於生產環境的金鑰材料,例如憑證和私密金鑰。 您可能需要為預生產測試產生不同的金鑰材料(通常使用自我簽署憑證授權單位)。 這些金鑰材料通常採用 Java 金鑰庫檔案的形式,格式為 JKS 或 PKCS #12,或者可能是 PEM 編碼的文字檔。 這些檔案類型中的每一種都需要不同的處理方式。

取得金鑰材料後,您需要將其轉換為可以傳遞給 Java 連線 API 的東西。 由於連線 API 可以透過多種方式進行設定,因此這裡可能會變得困難

  • 有些希望您提供金鑰庫和信任庫 java.security.KeyStore 實例。
  • 有些希望您提供 javax.net.ssl.KeyManagerjavax.net.ssl.TrustManager 實例。
  • 有些希望您提供 javax.net.ssl.SSLContext 實例。

SSL 的層級也相當低,因此您通常需要剝除幾層抽象才能找到需要使用來自 java.securityjava.net.ssl 套件的物件進行設定的東西。 例如,如果您想在 Spring RestTemplate 上設定 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 中提供,可以自動連線到其他 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 讓您能夠輕鬆地設定用於從應用程式連線到資料服務的用戶端程式庫。 這些用戶端程式庫是 API 的良好範例,這些 API 使用 Java 安全性和 SSL 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.* 屬性配置,以保護傳入連線的安全。 自 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 社群中所有即將舉行的活動。

查看全部