日本综合一区二区|亚洲中文天堂综合|日韩欧美自拍一区|男女精品天堂一区|欧美自拍第6页亚洲成人精品一区|亚洲黄色天堂一区二区成人|超碰91偷拍第一页|日韩av夜夜嗨中文字幕|久久蜜综合视频官网|精美人妻一区二区三区

RELATEED CONSULTING
相關(guān)咨詢(xún)
選擇下列產(chǎn)品馬上在線(xiàn)溝通
服務(wù)時(shí)間:8:30-17:00
你可能遇到了下面的問(wèn)題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營(yíng)銷(xiāo)解決方案
一次SSL握手異常,我發(fā)現(xiàn)JDK還有發(fā)行版區(qū)別

簡(jiǎn)介

最近,我們一個(gè)多機(jī)房部署的服務(wù),調(diào)用方反饋有問(wèn)題,在調(diào)用新加坡機(jī)房時(shí)正常,而調(diào)用印度機(jī)房則報(bào)SSL握手異常。

排查花了一些時(shí)間,同時(shí)也積累了一些經(jīng)驗(yàn),故記錄一下,讀完本文,你將了解到如下內(nèi)容:

  • SSL握手過(guò)程
  • SSL握手異常時(shí)的排查思路與工具
  • 同版本的JDK,也是有所差異的

廢話(huà)不多說(shuō),往下看...

發(fā)現(xiàn)問(wèn)題

調(diào)用方調(diào)用印度機(jī)房服務(wù)時(shí),報(bào)錯(cuò)信息如下:

這個(gè)異常是同事一直在看,經(jīng)過(guò)一翻搜索,懷疑是JDK版本的問(wèn)題,經(jīng)過(guò)詢(xún)問(wèn)調(diào)用方,發(fā)現(xiàn)調(diào)用方版本是1.8.0_91-b14,于是同事打算下載此版本JDK本地測(cè)試一下。

但這個(gè)版本JDK不太好找,于是同事就問(wèn)了下我,我也找了一會(huì)也沒(méi)找到,于是打算從源碼編譯一個(gè)此版本JDK。

經(jīng)過(guò)一段時(shí)間,我通過(guò)源碼編譯出來(lái)了這個(gè)版本的jdk,同時(shí)同事也在網(wǎng)上找到了一個(gè)此版本的JDK,如下:

JDK源碼:https://github.com/openjdk/jdk8u ,tag選擇jdk8u91-b14即可。

網(wǎng)上的JDK包:https://github.com/ojdkbuild/ojdkbuild/releases/download/1.8.0.91-3/java-1.8.0-openjdk-1.8.0.91-1.b14.el6.x86_64.zip

弄到1.8.0_91-b14版JDK后,我和同事都進(jìn)行了測(cè)試,奇怪的是,同事網(wǎng)上找的JDK重現(xiàn)了調(diào)用方的報(bào)錯(cuò),即新加坡機(jī)房正常,而印度機(jī)房SSL握手失敗,但我自己編譯的JDK則兩個(gè)機(jī)房都正常,我們可是相同版本的JDK?。?/p>

好家伙,現(xiàn)在有2個(gè)疑問(wèn)了,如下:

為啥新加坡機(jī)房正常,而印度機(jī)房SSL握手報(bào)錯(cuò)?

為啥相同版本的JDK,自己編譯的沒(méi)有問(wèn)題?

為啥SSL握手報(bào)錯(cuò)?

粗略來(lái)講,SSL握手過(guò)程如下:

客戶(hù)端發(fā)送Client Hello包給服務(wù)端,其中除了包含密鑰協(xié)商相關(guān)的數(shù)據(jù)外,還會(huì)告知自己支持的密碼套件列表。

服務(wù)端收到Client Hello包后,會(huì)給客戶(hù)端回復(fù)Server Hello,其中也包含了密鑰協(xié)商數(shù)據(jù),以及服務(wù)端選擇了哪個(gè)密碼套件。

但有一種情況是,客戶(hù)端第一步發(fā)送的所有密碼套件,服務(wù)端都不支持,因此服務(wù)端會(huì)回復(fù)一個(gè)SSL握手異常包,進(jìn)而導(dǎo)致客戶(hù)端失敗報(bào)錯(cuò)。

注:密碼套件,指的是加密系統(tǒng)將多種密碼學(xué)算法混合使用,以實(shí)現(xiàn)多種安全需求,如TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,使用ECDHE實(shí)現(xiàn)密鑰協(xié)商、RSA實(shí)現(xiàn)證書(shū)認(rèn)證、AES實(shí)現(xiàn)加密、SHA256實(shí)現(xiàn)消息防篡改。

如何確認(rèn)是否是上面原因呢?我進(jìn)行了如下測(cè)試:

添加JVM參數(shù)-Djavax.net.debug=SSL,并調(diào)用正常的新加坡機(jī)房,看看SSL握手選擇的是什么密碼套件。

$ bin/java -Djavax.net.debug=SSL SgSendRequest

可以看到,客戶(hù)端提供了很多密碼套件,服務(wù)端選擇了TLS_DHE_RSA_WITH_AES_128_GCM_SHA256,那么極有可能是印度機(jī)房不支持此密碼套件,導(dǎo)致印度機(jī)房請(qǐng)求失敗,可用curl確認(rèn)下:

使用curl以指定密碼套件DHE-RSA-AES128-GCM-SHA256訪問(wèn)印度機(jī)房。

$ curl -v https://in.xxx.be.srv.com --ciphers DHE-RSA-AES128-GCM-SHA256

可以發(fā)現(xiàn),印度機(jī)房確實(shí)不支持此密碼套件。

注:jdk密碼套件名稱(chēng)與curl的名稱(chēng)稍微有點(diǎn)不一致,curl的可以在這里查找 https://curl.se/docs/ssl-ciphers.html

這也就是說(shuō),此JDK支持的密碼學(xué)套件與印度機(jī)房支持的密碼學(xué)套件沒(méi)有交集,服務(wù)端無(wú)法選出一個(gè)雙方都支持的密碼套件,可以進(jìn)一步確認(rèn)下,如下:

jdk支持的密碼套件可以通過(guò)SSLServerSocketFactory.getSupportedCipherSuites()獲取。

$ bin/jrunscript -e "print(java.util.Arrays.toString(javax.net.ssl.SSLServerSocketFactory.getDefault().getSupportedCipherSuites()))"

印度機(jī)房支持的密碼套件可以使用nmap掃描獲取,如下:

$ nmap --script ssl-enum-ciphers -p 443 in.xxx.be.srv.com

經(jīng)過(guò)我的檢查,發(fā)現(xiàn)jdk的密碼套件與印度機(jī)房的密碼套件確實(shí)沒(méi)有交集,印度機(jī)房只支持一些較新的密碼套件,這就是調(diào)用印度機(jī)房服務(wù)時(shí)SSL握手失敗的原因。

用相同的方法,我也確認(rèn)了新加坡機(jī)房,發(fā)現(xiàn)新加坡機(jī)房的密碼套件與jdk的密碼套件有交集,而TLS_DHE_RSA_WITH_AES_128_GCM_SHA256就在其中。

要解決這個(gè)問(wèn)題也比較容易,要么讓調(diào)用方升級(jí)jdk以支持新的密碼套件,要么讓印度機(jī)房SRE調(diào)整SSL配置以支持舊的密碼套件,我們選擇了前者。

那么,還有一個(gè)問(wèn)題,為啥我自己編譯的同版本的JDK就沒(méi)有問(wèn)題呢?

為啥自行編譯的JDK沒(méi)有問(wèn)題?

有點(diǎn)迷惑,我用上面相同方法確認(rèn)了一下我自己編譯的JDK支持哪些套件,如下:

$ bin/jrunscript -e "print(java.util.Arrays.toString(javax.net.ssl.SSLServerSocketFactory.getDefault().getSupportedCipherSuites()))"

可以發(fā)現(xiàn),我自己編譯的JDK,支持ECDH系列的新密碼套件,這是為啥?

為了弄清區(qū)別,我使用問(wèn)題JDK進(jìn)行了調(diào)試,如下:

import javax.crypto.KeyAgreement;
import java.security.NoSuchAlgorithmException;

public class EcdhTest {
public static void main(String[] args) throws NoSuchAlgorithmException {
KeyAgreement ka = KeyAgreement.getInstance("ECDH");
System.out.println(ka);
}
}

在問(wèn)題JDK里面,會(huì)報(bào)如下異常:

$ bin/java EcdhTest
Exception in thread "main" java.security.NoSuchAlgorithmException: Algorithm ECDH not available
at javax.crypto.KeyAgreement.getInstance(KeyAgreement.java:184)
at EcdhTest.main(EcdhTest.java:6)

有異常就好辦了,只要順著異常產(chǎn)生的過(guò)程調(diào)試下去即可,大概調(diào)試了如下相關(guān)方法:

sun.security.ssl.JsseJce.getKeyAgreement("ECDH")  
sun.security.ec.SunEC

當(dāng)調(diào)試到SunEC類(lèi)時(shí),我發(fā)現(xiàn)在加載sunec動(dòng)態(tài)庫(kù)時(shí)會(huì)報(bào)錯(cuò),如下:

于是,我去問(wèn)題jdk目錄下查找這個(gè)動(dòng)態(tài)庫(kù)文件,動(dòng)態(tài)庫(kù)文件在Linux下一般是.so結(jié)尾,如下:

$ find | grep sunec
./jre/lib/ext/sunec.jar
./jre/lib/amd64/libsunec.so_DISABLED
./jre/lib/amd64/libsunec.diz

懵逼了,在這個(gè)問(wèn)題JDK里,libsunec.so?竟然被改名為了libsunec.so_DISABLED,而我看了下我自己編譯的JDK,這個(gè)文件是沒(méi)有改名的!

終于,第二個(gè)問(wèn)題也找到了原因,原來(lái)是網(wǎng)上找的這個(gè)JDK,通過(guò)改名libsunec.so將EC系列算法禁用了。

我大概看了會(huì)那個(gè)JDK下載頁(yè)面,這個(gè)JDK構(gòu)建時(shí)間挺久了,是RedHat早期為CentOS6構(gòu)建的一個(gè)JDK8版本,至于為啥要禁用EC系列算法,也沒(méi)找到相關(guān)解釋?zhuān)缓镁痛舜蜃 ?/p>

總結(jié)

這個(gè)問(wèn)題在報(bào)錯(cuò)能被穩(wěn)定重現(xiàn)出來(lái)時(shí),其實(shí)就不難了,但排查思路與使用到的工具還是挺值得分享的,如下:

  • 客戶(hù)端與服務(wù)端支持的密碼套件沒(méi)有交集,會(huì)導(dǎo)致SSL握手失敗。
  • 使用-Djavax.net.debug=SSL可以調(diào)試java的SSL握手過(guò)程。
  • 通過(guò)curl --ciphers指定客戶(hù)端密碼套件訪問(wèn)服務(wù)端,可以確認(rèn)服務(wù)端是否支持此密碼套件。
  • 通過(guò)SSLServerSocketFactory.getSupportedCipherSuites()可獲取JDK支持的密碼套件。
  • 使用nmap --script ssl-enum-ciphers可掃描出服務(wù)端支持的密碼套件。
  • 同樣版本的JDK,不同發(fā)行商發(fā)行的,也可能存在著差異。

文章名稱(chēng):一次SSL握手異常,我發(fā)現(xiàn)JDK還有發(fā)行版區(qū)別
文章起源:http://www.dlmjj.cn/article/djiejdh.html