A同事: 欸欸欸!LAG,我那邊HTTPS不能用耶!
LAG: 但我使用沒問題...?
LAG: B同事也沒問題。......C同事也是沒有問題。
好像每次引入變更,總有這總情況:明明都已經做過很多的檢查與測試了,就是有一些特殊狀況存在問題。
「每次引入的變更,都同時引入了新的問題」
百密總有一疏,特別是TLS這塊領域懂、我能請教到的人並不太多。今天分享兩個曾經遇到過比較奇葩的問題,以及後來的解決方式。
熟悉TLS交握方式最好,但今天不會詳細說明定位問題的方式。並且HTTP 1.0、HTTP 1.1、HTTP 2.0、HTTP 3.0的設計上都有差異(還區分SSLv2、SSLv3、TLS 1.0、TLS 1.1、TLS 1.2、TLS 1.3)。雖然不完全和TLS交握有關,但YouTube影片「QUIC核心原理和握手过程」仍推薦看看,覺得講解的蠻好懂的。
就像是前一天提到的:SNI需要與路由的host設定應匹配。
但光不匹配情況我就遇過3種:
零寬空格是最麻煩的,但不知道為什麼,那段時間就是經常看到。
先是在輸入的Excel處理過程出錯,後是憑證裡面Orz
那個時候還是使用Nginx,設定都完成了,檢查了數次憑證內容,瀏覽器還是出現警告。最後一個一個字檢查才發現問題。這種情況只能請生成憑證的單位重新產生一張新憑證。
域名在規範上不會使用大寫字符,但通常憑證內使用大寫字符,瀏覽器是可以匹配上,並不會出現警告。不過在APISIX可能就會出現以下錯誤訊息,而無法建立TLS連線:
failed to fetch ssl config: failed to find SNI: please check if the client requests via IP or us
es an outdated protocol. If you need to report an issue, provide a packet capture file of the TLS handshake.
這種情況有兩種做法:1. 重新生成憑證。2. 同下個情況,調整APISIX設定。
最後,可能直接使用IP方式提供存取,或是一些情況不會指定host,如預設路由等等情況。
也有可能是在測試情況直接使用IP,並在請求HEADER裡添加HOST
字段。這些情況可能都無法與APISIX建立TLS連線。(這種可以透過自行添加hosts檔案內容,然後改成domain連線)
儘管憑證內申明了使用IP,但APISIX仍有可能不視作SNI。
因此需要在設定中申明預設使用的SNI。請調整apisix_config/config.yaml
,在SSL區段添加fallback_sni
,並重啓APISIX。
ssl:
fallback_sni: "xn--55qx5d0y0ax0p39ed04a.com"
如此一來,對於不匹配的請求,就會嘗試使用符合預設SNI的憑證提供給Client建立連線。但注意:瀏覽器仍有可能出現憑證內容與請求不符合的警告。
還遇過一種情況,公司內有一些較舊的服務無法使用TLS 1.2之後的協議版本。奈何在Nginx轉換成APISIX過程中並沒有注意到APISIX預設不啓用TLS 1.0、TLS 1.1等已經不安全的協議,因而造成影響。後續與受影響單位協調,繼續開放支援TLS 1.0、TLS 1.1,在一年內完成轉移調整,待一年後移除相關協議的啓用設定。
为了安全考虑,APISIX 默认使用的加密套件不支持 TLSv1.1 以及更低的版本。 如果你需要启用 TLSv1.1 协议,请在 config.yaml 的配置项 apisix.ssl.ssl_ciphers 增加 TLSv1.1 协议所支持的加密套件。
---- SSL 协议
要啓用TLS 1.0、TLS 1.1,一個簡單方式同樣是調整apisix_config/config.yaml
。在設定裡面找到apisix.ssl
區塊,添加ssl_protocols
,並且可能需要啓用特定的ciphers,因此也要添加ssl_ciphers
,然後同樣重啓APISIX服務。
APISIX支援動態方式針對不同的路由調整,如有需求,請自行參考文檔。
ssl:
ssl_protocols: TLSv1 TLSv1.1 TLSv1.2 TLSv1.3
ssl_ciphers: TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ARIA256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ARIA128-GCM-SHA256:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-CAMELLIA256-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-CAMELLIA128-SHA256:ECDHE-RSA-AES256-SHA:ECDHE-RSA-AES128-SHA:AES256-GCM-SHA384:AES256-CCM8:AES256-CCM:ARIA256-GCM-SHA384:AES128-GCM-SHA256:AES128-CCM8:AES128-CCM:ARIA128-GCM-SHA256:AES256-SHA256:CAMELLIA256-SHA256:AES128-SHA256:CAMELLIA128-SHA256:AES256-SHA:CAMELLIA256-SHA:AES128-SHA:CAMELLIA128-SHA # ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES256-SHA:DHE-DSS-AES256-SHA:ECDHE-RSA-AES128-SHA:AES256-SHA:CAMELLIA256-SHA:AES128-SHA:CAMELLIA128-SHA
fallback_sni: "xn--55qx5d0y0ax0p39ed04a.com"
要檢查TLS 1.0和TLS 1.1是否啓用了,除了請需求單位再嘗試看看(🤣),還可以透過sslscan工具。同樣在Ubuntu軟體倉庫源裡有,可以直接透過apt install sslscan
安裝
使用方式很簡單,直接輸入命令sslscan https://<檢查的位置>
,例如:
sslscan https://xn--55qx5d0y0ax0p39ed04a.com:9443
這會得到憑證的基本資訊。包含主體(Subject)、別名(Altnames)和有效期限,也可以依此了解該憑證匹配的域名。
支援的SSL/TLS版本。下圖是APISIX 3.2.2版本預設支援情況:
綠色是設定無慮,白色無異常,紅色的話則建議調整。也就是如果啓用了TLS 1.0、TLS 1.1:
然後更進一步的可以看看支援的Cipher:
除了sslscan外,也可以使用openssl
和curl
檢查[^1],這兩個工具在通常的Linux發行版應該都預設帶上了:
[^1]: 這兩段程式碼,改寫自使用 OpenSSL 與 cURL 檢查網站伺服器支援哪幾種 Cipher Suites
TLS 1.2
SUPPORTED_CIPHERS=$(openssl ciphers -s -tls1_2)
IFS=':' read -r -A SUPPORTED_CIPHERS <<< $SUPPORTED_CIPHERS
for c in "${SUPPORTED_CIPHERS[@]}"
do
printf -v pad %30s
cipher=$c$pad
printf "Checking ${cipher:0:30} ... "
curl -k -s -S -o /dev/null --no-progress-meter --tls-max 1.2 https://xn--55qx5d0y0ax0p39ed04a.com:9443
if [ $? -eq 0 ]; then
echo OK
fi
done
TLS 1.3
SUPPORTED_CIPHERS=$(openssl ciphers -s -tls1_3)
IFS=':' read -r -A SUPPORTED_CIPHERS <<< $SUPPORTED_CIPHERS
for c in "${SUPPORTED_CIPHERS[@]}"
do
printf -v pad %30s
cipher=$c$pad
printf "Checking ${cipher:0:30} ... "
curl -k -s -S -o /dev/null --no-progress-meter --tls-max 1.3 --tls13-ciphers $c https://xn--55qx5d0y0ax0p39ed04a.com:9443
if [ $? -eq 0 ]; then
echo OK
fi
done