如何向 Java 應用程序伺服器添加額外的密碼套件?
從 java 應用程序呼叫第三方 API 時,我遇到了一些麻煩。外部 API 至少需要以下密碼之一:
TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 TLS_DHE_RSA_WITH_AES_128_GCM_SHA256
我按照此處的說明進行操作:https ://confluence.atlassian.com/stashkb/list-ciphers-used-by-jvm-679609085.html嘗試升級我的應用程序伺服器上的可用密碼。但是,升級後我仍然沒有看到列出的任何兼容密碼。
我懷疑問題是我的伺服器正在執行 jdk 1.7 。這是一個遺留應用程序,所以很遺憾我無法升級到更新的 jdk。有沒有辦法將這些密碼添加到我現有的 java 安裝中?
更新: 我想出瞭如何添加額外的密碼,但它似乎沒有幫助。在我的套接字工廠中,我添加了一些這樣的程式碼:
private Socket acceptOnlyTLS12(Socket socket) { if (!(socket instanceof SSLSocket)) return socket; SSLSocket sslSocket = (SSLSocket) socket; sslSocket.setEnabledProtocols(new String[] { "TLSv1.2" }); List<String> ciphers = new ArrayList<String>(Arrays.asList(sslSocket.getEnabledCipherSuites())); ciphers.add("TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256"); sslSocket.setEnabledCipherSuites(ciphers.toArray(new String[] {})); return sslSocket; }
我在某個地方還缺少另一個步驟嗎?是否有某種方法可以獲取有關 ssl 握手失敗原因的其他資訊?
我終於找到了一個解決方法,如果有點難看。我創建了一個向外部 API 發出 cURL 請求的 groovy 腳本。由於 cURL 可以使用最新的證書,因此我可以繞過因使用舊 JDK 所帶來的限制。它很笨拙,但它有效。
(1) 該網頁的日期為 2014 年;在 2017 年之後,Oracle Java 版本不再使用無限策略,在此之前(例如 7u80)它只對 128 位以上的對稱加密很重要,這只會影響 AES256 套件而不影響 AES128 套件。(它從未適用於 OpenJDK,儘管低於 8 的 OpenJDK 曾經/僅在主要的 Linux 發行版(如 RedHat 和 Debian)上可用,它們可以分配人員進行建構和打包;你不說你在使用哪個。)
(2) Java (1.)7確實支持您顯示的 CBC 密碼套件(不是 GCM 密碼套件,對於 7u171 以下的 Oracle 版本,AES256 確實需要無限策略)但僅在使用 TLS1.2 時(這些密碼套件不存在在較低版本的協議中),預設情況下 j7 禁用 TLS1.2(和 1.1)客戶端。
HttpsURLConnection
如果您使用(例如)明確地連接到此 API,new URL("https://something").openConnection()
您可以調整 socketfactory 以使用SSLContext.getInstance("TLSv1.2")
和/或明確地setEnabledProtocols
在套接字上使用。如果您使用其他中間件,例如 Apache HttpComponents,通常有類似的方法,但它們的細節有所不同;您需要向我們展示程式碼,這可能屬於 StackOverflow,而不是這裡。如果您正在呼叫一個在內部進行連接的庫,它可能有選項,也可能沒有。對於所有或許多呼叫方法,您可以更改預設值,SSLContext.setDefault()
或者HttpsURLConnection.setDefaultSSLSocketFacfory()
如果這些預設值沒有在相關程式碼中被覆蓋,並且進行這樣的全域更改不會對在同一 JVM 中執行的其他任何東西造成麻煩。或者(以及更多關於主題的內容!)如果您有足夠新的 j7 更新,我很確定他們向後移植了系統屬性
jdk.tls.client.protocols
,您可以將其設置為例如TLSv1,TLSv1.1,TLSv1.2
更改預設值而不更改程式碼(但同樣只有在沒有被覆蓋且沒有被覆蓋的情況下)傷害其他任何東西)。我不記得確切的時間,但肯定是在 7u80 之後,所以你只能在付費的 Oracle 支持或 OpenJDK 由其他人有償或無償支持的情況下擁有它。這很容易嘗試並且可能會奏效。