Android6.0使用Https出現Handshake failed錯誤

因爲微信的公衆號和小程序開發須要https,在使用過程當中發現Android6.0版本手機接口請求老是失敗,在細查之下發現跟https的證書有關,下面的方案通過驗證可行,轉過來看下;android

原博客:https://blog.csdn.net/duanbokan/article/details/50911148算法

Android6.0版本的,升級後,在測試咱們的應用時,忽然出現握手失敗錯誤:apache

可是在Android6.0如下版本中,並無出現該問題。小程序

1、Android6.0的一些修改

由於該問題僅僅出如今Android6.0版本中,所以,考慮是由版本升級引發的。查看Google給出的Android6.0修改文檔,發現如下兩點:tomcat

即:安全

  1. 從Android6.0以後將再也不支持HttpClient的使用,建議使用HttpURLConnection代替。
  2. Android6.0以後,在Https請求中,SSL層將再也不使用OpenSSL協議,改用本身的BoringSSL協議

2、分析

2.1 取消HttpClient

在咱們的項目中使用的是HttpClient執行Https請求,可是官方升級只是在API文檔中刪除了HttpClient相關的文件,可是並不影響其使用,用戶能夠經過如下兩種方法繼續使用:bash

  1. 使用Android6.0進行編譯,則須要添加 org.apache.http.legacy.jar,文件目錄:SDK\platforms\android-23\optional;或者是在AndroidStudio中的build.gradle文件中加入:服務器

    android {useLibrary 'org.apache.http.legacy'}微信

  2. 使用Android6.0如下版本進行編譯。測試

所以,排除該可能。

2.2 使用BoringSSL替換OpenSSL

由於考慮到是該問題引發的,所以回過頭從新對握手失敗緣由進行查看,發如今以前Log結尾部分忽略了一句話,也正是由於忽略這句話,致使以前思惟一直停在多是HttpClient被取消致使的,浪費了不少時間,握手失敗後,在最後邊Log中,出現這樣的信息:

關鍵字:BAD_DH_P_LENGTH

通過一番尋找,發現意思應該是Diffie-Hellman的p參數長度錯誤。主要參考文章:謝謝大神——鏈接

經過對帖子的閱讀和資料的查找,總結其主要緣由在於:

Https創建鏈接以前,會進行屢次握手,即單向認證和雙向認證。在該過程當中,客戶端會將本身支持的全部加密方式發送給服務端,供服務端選擇,服務端選擇好加密程度較高的加密方式後,會以明文或者是客戶端私鑰加密密文的方式發送給客戶端。

具體認證過程可參考個人上一篇文章:Https單向認證和雙向認證

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

終於找到問題所在了,總結這個糾結的過程,我只想說:必定要認真看Log!!!

3、解決方案

經過閱讀上邊提到的大神寫的帖子,發現兩種能夠解決的辦法:

  1. 升級JDK到8(條件限制,未通過測試)

  2. 配置Tomcat服務器,限制加密方式:

    修改Tomcat服務器conf/server.xml文件中和Https有關的Connector節點,添加ciphers用於指定密鑰:

    <Connector 
        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錯誤。

相關文章
相關標籤/搜索