1. 程式人生 > >Android 6.0 HTTPS SSL 無法訪問,提示Handshake failed(握手失敗),解決方案

Android 6.0 HTTPS SSL 無法訪問,提示Handshake failed(握手失敗),解決方案

前言

之前開發的一個專案使用的是http請求,但是安全公司給出了一個安全報告,建議使用https協議來訪問網路資源,使用私簽證書來實現了https。Android 6.0以下的版本均可以使用,Android 6.0及以上的機型請求成功,並且在logcat中有Handshake failed的Exception。

分析

Android 6.0以下可以訪問,6.0及以上不可以,初步判斷是因為Android版本更新造成的,
經過一番google之,根據本地報錯含有BAD_DH_P_LENGTH關鍵字。
確定問題出現在Java ssl 加密漏洞上。

在握手過程中,必定會涉及到公鑰加密,私鑰解密的過程,而該過程中,當服務端選擇使用諸如TLS_DHE_RSA_WITH_AES_128_CBC_SHA等演算法進行加密時,需要使用到Diffie-Hellman演算法進行加密解密,通過閱讀Diffie-Hellman演算法的介紹,發現在加密解密計算過程中,會使用到兩個引數,一個是q,一個是a,而在JDK8之前,伺服器端提供的q引數只是用了768bit的長度,而不足1024bit則存在相應的安全漏洞,會被替換後的BroingSSL拒絕,因此出現了Handshake failed錯誤。

解決方案

方案一、修改tomcat

配置Tomcat伺服器,限制加密方式:
修改Tomcat伺服器conf/server.xml檔案中和Https有關的Connector節點,新增ciphers用於指定金鑰:
SSLEnabled=”true”
clientAuth=”false”
connectionTimeout=”20000”
keystoreFile=”/usr/xinwei/tienlen/apache-tomcat-https/server.keystore”
keystorePass=”xinwei”
maxThreads=”150”
port=”443”
protocol=”org.apache.coyote.http11.Http11Protocol”
redirectPort=”8443”
scheme=”https”
secure=”true”
ciphers=”TLS_RSA_WITH_AES_128_CBC_SHA256,
TLS_RSA_WITH_AES_128_CBC_SHA,
TLS_RSA_WITH_AES_256_CBC_SHA256,
TLS_RSA_WITH_AES_256_CBC_SHA,
SSL_RSA_WITH_3DES_EDE_CBC_SHA”
sslProtocol=”TLS”
truststoreFile=”/usr/xinwei/tienlen/apache-tomcat-https/server.keystore”
truststorePass=”密碼”
/>

新增完該配置後,重啟,測試,Android6.0版本沒有再發現Handshake failed錯誤。

很遺憾,我們伺服器使用的是JDK 1.6、tomcat 7 ,配置ciphers,啟動服務後會報錯,報錯原因是不識別加密方式、所以我們沒有采用這個方式,應該是因為TSL協議的版本問題

方案二、升級JDK至1.8版本

我們採用這個方式,成功修復了SSL Handshake failed的問題,只要程式碼中沒有使用Java8 不再相容的特性,一般沒有問題。

方案三、使用OKhttp時客戶端修改SSL配置客戶端加密套件(未驗證,收錄)

OkHttpClient okHttpClient = new
OkHttpClient.Builder() .connectTimeout(15, TimeUnit.SECONDS) .readTimeout(15, TimeUnit.SECONDS) .writeTimeout(15, TimeUnit.SECONDS) .addNetworkInterceptor(new StethoInterceptor()) .followSslRedirects(true) .connectionSpecs(Collections.singletonList(getConnectionSpec())) .build(); private static ConnectionSpec getConnectionSpec() { ConnectionSpec spec = new ConnectionSpec.Builder(ConnectionSpec.MODERN_TLS).tlsVersions(TlsVersion.TLS_1_0).cipherSuites(CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA256, CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA, CipherSuite.TLS_RSA_WITH_AES_256_CBC_SHA256, CipherSuite.TLS_RSA_WITH_AES_256_CBC_SHA, CipherSuite.TLS_RSA_WITH_3DES_EDE_CBC_SHA).build(); return spec; }
  • https三次握手:
    • 客戶端傳送 TLS版本號 加密套件(這裡) 隨機數 hello
    • 服務端根據客戶端傳送的加密套件、TLS版本號 選擇對應的加密協議及套件 把加密協議、加密套件、隨機數、服務端證書、hello傳送給客戶端
    • 客戶端收到資訊後 生成隨機數(通過公鑰進行加密) 編碼結速通知 握手結束通知
    • 服務端 通過私鑰解密 編碼改變通知 握手結束通知
    • 對稱加密資料傳輸