Certbot 生成的設定檔在不同版本 Apache 間移轉的小坑

Apache 從版本 2.4.8 開始,廢除了 SSLCertificateChainFile 這個 directive,直接由 SSLCertificateFile 處理整串憑證,降版的時候要小心。

症狀

有的時候瀏覽器可以正常瀏覽,也就是說憑證是有效的,但是用 command-line tools 的時候網站的憑證卻會驗證不通過。

例如:

wget https://incomplete-chain.badssl.com/

原理

憑證的簽發通常不會是直接由 root CA 直接簽發憑證給用戶(在這個案例裡就是 HTTPS 網站),而是 root CA 簽發憑證給 intermediate CA,再由 intermediate CA 簽發憑證給用戶。一般來說,在網頁瀏覽者的瀏覽器或作業系統裡,通常只存 root CA 的憑證資訊。然而,整套信任鏈的建立,仍然需要 intermediate CA 的憑證資訊,所以 HTTPS 伺服器在服務的時候,不只要提供自身的憑證,也要提供簽發自身憑證的 intermediate CA 憑證資訊。

用 OpenSSL 來看一個正常的範例:

echo -n | openssl s_client -connect badssl.com:443 -servername badssl.com -showcerts | less

裡面可以看到兩份憑證。

Apache 從版本 2.4.8 開始,直接把自身以及 intermediate CA 的憑證用單一檔案吃進來,過往則是分成兩個不同的檔案吃。Certbot 在替 Apache 站加 HTTPS 憑證及相關設定的時候,也會很聰明地判斷你所使用的 Apache 版本,生成符合該版本的設定。

如果是用 Certbot 重新跑一次設定當然不會有問題;直接把先前生成的設定檔複製一份來用的話,Apache 升版本應該也會因為新版不支援舊的 SSLCertificateChainFile directive,產生錯誤訊息而被發現。問題發生於新版降級到舊版的狀況,因為這個時候 Apache 不會有錯誤訊息,但是它卻只會從 SSLCertificateFile 所指向的 fullchain.pem 裡面拉出其中的自身憑證來用,並不處理 intermediate CA 的憑證資訊。

用 OpenSSL 來看一個這樣的範例:

echo -n | openssl s_client -connect incomplete-chain.badssl.com:443 -servername incomplete-chain.badssl.com -showcerts | less

這裡就只有一份憑證了。

在某些情況下瀏覽者並不會發現問題,因為用 Let’s Encrypt 的網站很多,瀏覽器有可能快取了從其他網站那裡拿到,剛剛好可以給你網站用的 intermediate CA 憑證資訊。但在沒有快取,或是快取被清掉的環境下,就會跳出憑證驗證不通過的警告。

修正

降版時把設定檔裡的

SSLCertificateFile /etc/letsencrypt/live/example.com/fullchain.pem

改成分開的

SSLCertificateFile /etc/letsencrypt/live/example.com/cert.pem
SSLCertificateChainFile /etc/letsencrypt/live/example.com/chain.pem

反之(升版時)則逆向操作。

修正完畢後可以再用上述的 OpenSSL 檢查法確認伺服器是否正常給出所有所需憑證。

參考資料

Posted in Technical.

Leave a Reply

Your email address will not be published. Required fields are marked *

Captcha loading...