簡體   English   中英

java SSL客戶端應用程序如何支持多個TrustStores

[英]How support multiple TrustStores in java SSL client application

在我們的 java 應用程序中,我們需要使用 https 協議與 SSL 上的服務器列表進行通信。 要通信的服務器列表將在運行時更改。 最初我們沒有任何服務器的證書。 在運行時,我們將獲取新的服務器證書並將公鑰證書添加到信任庫中; 並且與服務器的任何新 https 連接都應使用更新的信任存儲。

我們認為我們應該使用兩個信任存儲,一個 cacerts(默認一個與 jre 一起提供)和另一個包含我們在列表中動態添加/刪除的服務器的證書。 這將確保我們不會修改 java 的默認 TrustStore(cacerts)。

請建議如何實現這一點。 此外,是否有任何方法可以僅對 java 中的特定線程使用特定的信任庫,以便其他(現有的和新的)線程仍應使用默認的 java trueststore(cacerts),並且一個特定的線程將使用特定的信任庫服務器。

謝謝你,迪帕克

如果要動態導入證書,可能需要使用自定義x509TrustManager 這是在配置SSLContext時完成的,它本身用於創建SSLSocketFactorySSLEngine

jSSLutils是一個庫,可讓您包裝現有的信任管理器並自定義某些設置。 你不需要它,但它可能會有所幫助。

這將沿着以下路線進行:

PKIXSSLContextFactory sslContextFactory = new PKIXSSLContextFactory();
sslContextFactory.setTrustManagerWrapper(new X509TrustManagerWrapper() {
    @Override
    public X509TrustManager wrapTrustManager(final X509TrustManager origManager) {
        return new X509TrustManager() { 
            @Override
            public X509Certificate[] getAcceptedIssuers() {
                return origManager.getAcceptedIssuers();
            }

            @Override
            public void checkServerTrusted(X509Certificate[] chain,
                                                   String authType)
                    throws CertificateException {
                try {
                    // This will call the default trust manager
                    // which will throw an exception if it doesn't know the certificate
                    origManager.checkServerTrusted(chain, authType);
                } catch (CertificateException e) {
                    // If it throws an exception, check what this exception is
                    // the server certificate is in chain[0], you could
                    // implement a callback to the user to accept/refuse
                }
            }

            @Override
            public void checkClientTrusted(X509Certificate[] chain,
                                                   String authType)
                    throws CertificateException {
                origManager.checkClientTrusted(chain, authType);
            }
        };
    }
});
SSLContext sslContext = sslContextFactory.buildSSLContext();

(PKIX)SSLContextFactoryX509TrustManagerWrapper來自 jSSLutils,但其余的可用於 J2SE/J2EE。)

您可能想要捕獲一些CertificateException s (請參閱子類)。 如果您對用戶進行回調,則 SSL/TLS 連接可能會在第一次失敗,因為 SSL/TLS 握手超時(如果回調需要很長時間才能得到回復。)

然后,您可以使用SSLContext.setSSLContext(...) (來自 Java 6)將此SSLContext作為您的默認設置,但這不一定是一個好主意。 如果可以,請將SSLContext傳遞給建立 SSL/TLS 連接的庫。 這是如何完成的,但例如,Apache HTTP Client 4.x 有多個選項來配置其 SSL 設置,其中之一是通過傳遞KeyStore ,另一個是通過傳遞SSLContext

通過檢查X509TrustManager的當前線程,您還可以針對每個線程而不是每個將要連接的對象(依賴於庫):這可能會使事情在同步和線程管理/“意識”方面變得更加復雜信托經理。

這個問題太老了,我懷疑我的一點能幫助任何人,但這里是......

如果你想在不改變代碼的情況下解決 OP(原始海報)的問題,你可以配置你的 JVM(我只用 Tomcat 測試過)來支持 OP 所需的配置:

  1. 單獨留下“打包”的 JDK cacerts 文件
  2. 將您的證書導入一個單獨的文件,並讓您的 JAVA 應用程序“信任”它們

我曾經只是將我的附加證書導入到一個單獨的文件中,然后在我的 JVM 啟動中使用參數-Djavax.net.ssl.trustStore=$JAVA_HOME/jre/lib/security/jssecacerts並取得了巨大的成功,但我猜最近(有點)JAVA 安全問題改變了與 SDK 一起分發的 cacerts 文件的自動包含。

所以我從這篇文章和這些頁面中找到了一個使用英特爾的漂亮解決方案(有一些小改動):

我曾經做過的事情:

  • 將 JVM trustStore 參數設置為我單獨的密鑰庫文件(我會將其他證書導入其中),如下所示

我現在做什么:

  • 將 trustStore 參數設置為“打包”的 cacerts 文件
  • 將 keyStore 參數設置為我的“附加證書”文件
  • 將 keyStorePassword 參數設置為我的 keyStore 的密碼(默認為 changeit)

它的樣子:

-Djavax.net.ssl.trustStore=$JAVA_HOME/jre/lib/security/cacerts \
-Djavax.net.ssl.keyStore=$JAVA_HOME/jre/lib/security/jssecacerts \
-Djavax.net.ssl.keyStorePassword="changeit" \

希望這對某人有幫助。 我不是 100% 您需要指定 keyStore 密碼,因為您沒有使用 trustStore,但是當您這樣做時它可以工作。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM