配置HTTPS,公鑰證書有效期短怎麼辦?

無尾熊二發表於2018-02-05

最近在配置Android客戶端的Https時,發現運維同事給我的公鑰證書的有效期只有3個月,如果直接使用這個證書對Https進行配置,那麼三個月以後,線上的App就會因為證書過期,造成所有Https請求失敗,進而無法從伺服器獲取資料,這是完全不能接受的。

可能這個問題不是很普遍,其一,運維同事提供給你的證書可能有效期很長;其二,如果給你的是中間證書或者根證書,這些證書有效期本身就比較長,但是畢竟我遇到了,還是準備和大家分享一下,幫助遇到此坑的同學成功爬坑。

文章以問答的形式展開,總共涉及三個問題。因為這塊其實涉及的知識面很廣,我還沒有完全掌握,有些地方也只是瞭解的程度,所以有說的不對的地方,還望指正。但是按照文章進行配置,成功解決上面的問題還是沒問題的。

一、為什麼App需要在本地對Https做單獨的證書配置?

在SSL/TLS握手的過程中,需要對伺服器傳送過來的公鑰證書進行校驗,判斷證書是否有效。

按道理,如果這個證書是一個被廣泛認可的CA機構簽發的證書,因為該機構的“根”證書可能已經儲存在Android系統中,那麼在證書驗證的過程中,通過證書鏈連結到對應的根證書,就可以完成驗證。這種情況不需要自己在app本地配置證書。

那在什麼情況下需要在App本地配置證書呢?

目前我遇到的情況有兩種:

  1. 伺服器公鑰證書使用的是自簽名證書
  2. 伺服器公鑰證書使用的是根證書未被瀏覽器接受的CA機構簽發的證書(比如Let's encrypt)

為什麼在這兩種情況下需要在App本地配置證書呢?

簡單來說,這兩種情況如果不在App本地配置證書,HTTPS的SSL/TLS握手過程就不會成功,HTTPS連線就不能夠建立。那麼為什麼握手不能成功呢?因為簽發這兩種證書的CA機構,其根證書並不在公認的可信任範圍內,所以其根證書並不會預設儲存在Android系統中。在SSL/TLS握手過程中,當伺服器將其公鑰證書傳送給App後,這個公鑰證書在證書鏈驗證過程中,由於不能連結到系統自帶的根證書,從而造成證書校驗失敗,進而造成SSL/TLS握手失敗。

所以在上面兩種情況下,就需要在App本地配置“證書”,協助完成握手過程中的證書校驗。

二、如何配置以及為什麼這麼配置?

配置其實很簡單,網上有不少文章,這裡就不詳細介紹了,推薦張鴻洋的文章: Android Https相關完全解析 當OkHttp遇到Https

公鑰證書我瞭解的有兩種驗證方式。一種是證書鏈校驗,通過該公鑰證書連結到系統儲存的根證書,說明證書有效;另一種是對比App本地儲存證書的編碼與伺服器傳送證書的編碼,如果一致,說明證書有效。

關於第二種驗證方式,讀過原始碼,不過因為實在涉及的知識面太廣了,沒能整的太明白,有興趣的同學可以看看JDK中PKIXValidator這個類,它裡面有個方法叫
engineValidate()
, 其中有一個
if (trustedCerts.contains(cert) ...
語句。

綜上一和二所述,自簽名證書和“小”CA機構(其實一點都不小,有的很大)簽發的證書,為了驗證其有效性,必須在App本地為校驗過程提供所需的證書。

三、解決證書有效期短的問題

按照上面第二個問答的說法,我們分兩種情況進行分析。假設App本地儲存的證書為A,伺服器在握手階段傳送給App的證書為B,證書B到其根證書鏈路上的證書為C。

第一種 通過證書編碼對比進行證書校驗

這種方式下,如果證書A有效期較短,就會遇到與我一樣的問題。那麼很簡單,我們只要使用一個有效期長一點的證書替換即可。

但是問題來了,編碼比對方式下,App本地儲存的證書A只能是與伺服器在握手階段傳送給App的證書B相同的證書,即A必須與B是同一個證書,這就限制了可用證書的數量,如果B有效期短,我們就沒有辦法將A替換為一個有效期長的證書。

第二種 通過證書鏈進行證書校驗

這種方式下,因為只要App本地儲存的證書是證書B到其根證書鏈路上的任意一個證書,在SSL/TLS握手階段都能成功完成證書校驗,所以App本地儲存的證書有很多個可選,只要找到其中一個有效期夠長的即可。一般選擇中間證書或根證書比較合理。

綜上所述,其實只要按照網上配置Https證書的文章進行正常配置,然後選擇一個有效期長的證書放到App中即可解決問題。

四、結語

像我們公司使用CA機構的是LetsEncrypt,按道理只要將LetsEncrypt的根證書放到App本地即可,但是實際操作過程中發現網路請求因為沒找到根證書失敗了,真是邪門了。仔細分析後發現,因為LetsEncrypt的根證書在瀏覽器中是不被預設支援的,所以我們的公鑰證書並不是直接使用LetsEncrypt的根證書或中間證書(使用LetsEncrypt的根證書進行簽名版本)進行簽名的,而是使用的LetsEncrypt頒發的由機構IdenTrust交叉簽名的中間證書。在我把這個中間證書放到App中後,網路請求ok,有效期短的問題解決。

LetsEncrypt根證書和中間證書的下載地址:letsencrypt.org/certificate…

希望通過這個文章,能夠給第一次做相關工作的朋友提供一些幫助。

相關文章