新四季網

hacknet入侵失敗變黑屏(故障分析Bad)

2023-10-19 01:24:55 1

作者:陳俊聰

任職於中移信息基礎平臺部資料庫組,負責 mysql 資料庫運維工作。

本文來源:原創投稿

*愛可生開源社區出品,原創內容未經授權不得隨意使用,轉載請聯繫小編並註明來源。

引言

作為一名 DBA 碰到過升級出問題需要回退麼?碰到過回退還解決不了問題麼?我有幸遇到了一次兇險的升級「血案」。

問題來自協助客戶升級 MySQL,以修復一個安全漏洞。

升級版本為 5.7.30,但這個問題源於 5.7.28,並且影響 5.7.28 以上的版本,所以文章主要對比 5.7.27 和 5.7.28 版本。

注意不是 bug,後面會詳細說明!

一、現象

MySQL 從 5.7.27 升級到 5.7.30。完成後應用連接測試發現頁面異常,mysql error 日誌顯示:

2020-05-05T22:10:57.976402 08:00 2 [Note] Bad handshake

沒有報錯,但這條 Note 級別的日誌,引起了我的注意,之前從來沒有見過。由於時間緊急,決定先回退 MySQL 版本。回退後,問題未能解決。

Bad handshake,"不好的握手",網上查了資料,發現和 ssl 可能有關。這時業務也發來應用日誌,日誌有明顯的 SSL 相關報錯。

然後,我們去檢查了 jdbc 連接串,連接串使用了 useSSL=true,改為 useSSL=false 後解決了。

二、分析

我們搭建了一套 java 應用環境,在 5.7.27 版本和 5.7.28 版本分別測試了發生故障時的 jdbc 串:

spring.datasource.url=jdbc:mysql://192.168.199.198:3307/springbootdb?useUnicode=true&useSSL=true&characterEncoding=utf8

5.7.27 版本

1. 默認關閉了 SSL

mysql> select @@version; ------------ | @@version | ------------ | 5.7.27-log | ------------ 1 row in set (0.00 sec)mysql> show variables like '%ssl%'; --------------- ---------- | Variable_name | Value | --------------- ---------- | have_openssl | DISABLED || have_ssl | DISABLED || ssl_ca | || ssl_capath | || ssl_cert | || ssl_cipher | || ssl_crl | || ssl_crlpath | || ssl_key | | --------------- ---------- 9 rows in set (0.00 sec)

2. 應用頁面正常

3. tomcat 日誌正常

4. 抓包,確實沒有用到 SSL,SQL 的明文被我抓出來了

[root@fander ~]# tcpdump -i ens33 port 3307 -l -s 0 -w - | stringstcpdump: listening on ens33, link-type EN10MB (Ethernet), capture size 262144 bytes^rY^,]select id, province_id, city_name, description from city

5. mysql err log 正常

小結

5.7.27 版本下,jdbc 連接串錯誤地配置了 useSSL=true,並不會有問題,因為資料庫不支持 SSL,所以連接實際上並不會使用到 SSL,一切正常。

5.7.28 版本

1. 升級後,默認居然開了 SSL

mysql> show variables like '%ssl%'; --------------- ----------------- | Variable_name | Value | --------------- ----------------- | have_openssl | YES || have_ssl | YES || ssl_ca | ca.pem || ssl_capath | || ssl_cert | server-cert.pem || ssl_cipher | || ssl_crl | || ssl_crlpath | || ssl_key | server-key.pem | --------------- ----------------- 9 rows in set (0.00 sec)

2. 應用頁面異常

3. tomcat 日誌異常

上面日誌,能看出是 SSL 相關異常。並且能發現一個關鍵的報錯,是握手異常,並且有證書相關的報錯。 Caused by: javax.net.ssl.SSLHandshakeException: java.security.cert.CertPathValidatorException: Path does not chain with any of the trust anchors後面我證實了,jdbc 連接要求 SSL 和 證書認證要一起使用。

4. 抓包顯示有加密信息,沒有抓取到 SQL

[root@fander ~]# tcpdump -i ens33 port 3307 -l -s 0 -w - | stringstcpdump: listening on ens33, link-type EN10MB (Ethernet), capture size 262144 bytes@8q=*8q= P@8q= 5.7.30-log=LQIKF7mysql_native_password8q=}P@8q=}B 8q=}P@8q=}@8q=}00<5MySQL_Server_5.7.30_Auto_Generated_Server_Certificate0 2nh=zFx3[x=o(*c0Ty5B0A,IY-{u60<1:081MySQL_Server_5.7.30_Auto_Generated_CA_Certificate0200506110938Z300504110938Z0*[]dG^!!$y[(jkh(nPjdVU{hMMojbU38P3.^Z

5. mysql err log 顯示 "Bad handshake"

2020-05-06T19:12:13.107321 08:00 2 [Note] Bad handshake

小結

5.7.28 版本下,jdbc 連接串錯誤地配置了 useSSL=true,會有問題,因為資料庫支持 SSL,所以連接實際上應用連接會真的去使用 SSL,但是因為證書問題,導致連接失敗,造成了這次升級故障。

不加 useSSL 試試

有一些客戶的連接串,是沒有使用 useSSL 參數的。

於是,我去掉 useSSL=true,把連接串改為

spring.datasource.url=jdbc:mysql://192.168.199.198:3307/springbootdb?useUnicode=true&characterEncoding=utf8

發現一切正常,但 tomcat 日誌有以下的 warnings:

Wed May 06 20:54:47 CST 2020 WARN: Establishing SSL connection without server's identity verification is not recommended. According to MySQL 5.5.45 , 5.6.26 and 5.7.6 requirements SSL connection must be established by default if explicit option isn't set. For compliance with existing applications not using SSL the verifyServerCertificate property is set to 'false'. You need either to explicitly disable SSL by setting useSSL=false, or set useSSL=true and provide truststore for server certificate verification.

翻譯:

不建議在未經伺服器身份驗證的情況下建立 SSL 連接。根據 MySQL 5.5.45 、5.6.26 和 5.7.6 的要求,如果未設置顯式選項,則默認情況下必須建立 SSL 連接。為了符合不使用 SSL 的現有應用程式,verifyServerCertificate 屬性設置為「false」。您需要通過設置 useSSL=false 顯式禁用 SSL,或者設置 useSSL=true 並為伺服器證書驗證提供 truststore。

從這裡的報錯,我發現了另外一個連接串參數,verifyServerCertificate,這個參數默認為 true,表示要驗證伺服器證書。

測試得出了以下表格:

三、原因

原因就是連接串錯誤地設置了 useSSL=true。

在 5.7.27 版本由於實際上不支持 SSL 連接,所以設置 useSSL 居然不會報錯,而會降級使用非 SSL 連接;而在 5.7.28 版本,實際上支持了 SSL 連接,所以根據 jdbc 配置 useSSL=true,連接會真的採用 SSL,但應用伺服器並沒有為伺服器證書驗證提供 truststore 文件,所以報錯了。

問題一:為什麼 5.7.28 才支持 SSL?

翻閱官方文檔 5.7.28 的 release notes,並沒有發現新支持 SSL 的描述,所以應該原本也是支持 SSL 的。實際上的確如此,對於非 openssl 編譯的 MySQL(5.7.27 及之前版本),可以採用 Linux 自帶的 openssl 和 MySQL 自帶的工具 mysql_ssl_rsa_setup,來生成"SSL 密鑰和證書文件",以支持 SSL 連接。

注意:Only OpenSSL

以往 MySQL 社區版默認是使用 yassl 編譯,企業版默認使用 openssl 編譯,手動編譯時可以選擇 yassl 或 openssl。

目前僅支持 OpenSSL,yassl 被移除了,默認編譯用的是 openssl,社區版和企業版支持並且只支持 openssl 作為其 SSL 庫。

至於為什麼要使用 openssl 替代 yassl,我們不展開討論。

在 mysqld.cc 源碼裡可以看到相關的一些代碼改動,

左邊 5.7.28,定義了 openssl,則 init-rsa_keys

右邊 5.7.27,定義了 openssl,並且沒有定義 yassl,才 init_rsa_keys。

由於 5.7.27 默認是 yassl 編譯的,所以實際上不會執行 init_rsa_keys 那段代碼。懷疑就是這個改動致使 5.7.28 才支持 SSL。

準確地說,是 5.7.28 才默認支持 SSL,之前版本需要手動使用工具 mysql_ssl_rsa_setup 來生成"SSL 密鑰和證書文件",以支持 SSL 連接。

1. 5.7.28 啟動資料庫時,會在數據目錄自動生成以下文件,而 5.7.27 版本並沒有。

ca-key.pemca.pemclient-cert.pemclient-key.pemprivate_key.pempublic_key.pemserver-cert.pemserver-key.pem

這些文件實際上就是"SSL 密鑰和證書文件",用於支持 SSL 連接。

2. 那麼為什麼 5.7.28 會自動生成這些文件?

mysql --verbose --help |less --auto-generate-certs Auto generate SSL certificates at server startup if --ssl is set to ON and none of the other SSL system variables are specified and certificate/key files are not present in data directory. (Defaults to on; use --skip-auto-generate-certs to disable.)

在 5.7.28 版本,存在該伺服器參數,但 5.7.27 未見此參數。

參數寫的很清楚,默認是開的,用於自動生成"SSL 密鑰和證書文件",如果數據目錄沒有這堆文件的話。

相關的參數,還有這些:

auto_generate_certssha256_password_auto_generate_rsa_keyssha256_password_private_key_pathsha256_password_public_key_pathRsa_public_key

官方文檔並沒有告訴我們這些參數是 5.7.28 新增的,原因是因為這些參數壓根就不是新增的!這些參數是一直都有的!

如果你的 MySQL 源碼編譯時用 openssl,替代 yassl,那就有這些參數!

所以 Only OpenSSL 這個新特性,實際上影響比官方文檔寫的要大,因為他實際上影響了 MySQL 參數!影響了 MySQL 默認開啟了 SSL 的支持!

問題二:為什麼降級回退 MySQL 沒有解決問題?

MySQL 5.7.28 啟動的時候,會自動生成這些"SSL 密鑰和證書文件",所以實際上開啟了 SSL 支持。回退 MySQL 5.7.27 時,這些文件和元數據無關,mysql_upgrade 程序是不會幫你刪除這些"SSL 密鑰和證書文件"的,所以回退後,5.7.27 實際上也開啟了 SSL 支持!這導致我那個錯誤配置 useSSL=true 但沒有配置 truststore 文件的應用程式報錯。

討論解決辦法

既然,有沒有這堆文件,會導致實際上是否開啟 SSL,那麼解決辦法可以是:

1. 刪除這堆文件,然後重啟 MySQL。

在回退後的 5.7.27 版本是可以這麼操作,但我們總歸要升級回去 5.7.28 的,而5.7.28 啟動又會自動生成這堆文件,開啟 SSL,所以這方法不行。

2. 刪除這堆文件的某個文件,然後重啟 MySQL。

這個方法看起來是可行的,例如刪除了 ca.pem 這個文件,文件不全會導致 SSL disabled,並且 mysqld 判斷數據目錄有部分 pem 文件,於是不會重新生成。但這方法忽略了一個可能,就是如果資料庫通過 Xtrabackup 物理熱備重做資料庫後,因為 Xtrabackup 實際上不會備份任何 pem 文件,所以資料庫重做啟動後,因 mysqld 判斷數據目錄沒有"SSL 密鑰和證書文件",這堆文件會全部重新生成。所以這方法不可行。

3. 配置 auto_generate_certs=off

讓不生成 cert 文件,即可默認 SSL disabled。

建議的解決辦法

因為 5.7.27 之前實際上默認是不支持 SSL 連接的,所以為了升級資料庫保持原樣,只需要配置文件新增以下配置即可。

[mysqld]skip_ssl

這方法,可以忽略"SSL 密鑰和證書文件" ,不啟用 ssl 。

總結

文章分享了 jdbc 應該如何配置,並且分享了一起官方文檔沒有提及的"默認參數變化"引起的升級故障,建議大家升級之前測試一下,對比一下參數,不要過度依賴於官方 release notes 文檔。

,
同类文章
葬禮的夢想

葬禮的夢想

夢見葬禮,我得到了這個夢想,五個要素的五個要素,水火只好,主要名字在外面,職業生涯良好,一切都應該對待他人治療誠意,由於小,吉利的冬天夢想,秋天的夢是不吉利的
找到手機是什麼意思?

找到手機是什麼意思?

找到手機是什麼意思?五次選舉的五個要素是兩名士兵的跡象。與他溝通很好。這是非常財富,它擅長運作,職業是仙人的標誌。單身男人有這個夢想,主要生活可以有人幫忙
我不怎麼想?

我不怎麼想?

我做了什麼意味著看到米飯烹飪?我得到了這個夢想,五線的主要土壤,但是Tu Ke水是錢的跡象,職業生涯更加真誠。他真誠地誠實。這是豐富的,這是夏瑞的巨星
夢想你的意思是什麼?

夢想你的意思是什麼?

你是什​​麼意思夢想的夢想?夢想,主要木材的五個要素,水的跡象,主營業務,主營業務,案子應該抓住魅力,不能疏忽,春天夢想的吉利夢想夏天的夢想不幸。詢問學者夢想
拯救夢想

拯救夢想

拯救夢想什麼意思?你夢想著拯救人嗎?拯救人們的夢想有一個現實,也有夢想的主觀想像力,請參閱週宮官方網站拯救人民夢想的詳細解釋。夢想著敵人被拯救出來
2022愛方向和生日是在[質量個性]中

2022愛方向和生日是在[質量個性]中

[救生員]有人說,在出生88天之前,胎兒已經知道哪天的出生,如何有優質的個性,將走在什麼樣的愛情之旅,將與生活生活有什么生活。今天
夢想切割剪裁

夢想切割剪裁

夢想切割剪裁什麼意思?你夢想切你的手是好的嗎?夢想切割手工切割手有一個真正的影響和反應,也有夢想的主觀想像力。請參閱官方網站夢想的細節,以削減手
夢想著親人死了

夢想著親人死了

夢想著親人死了什麼意思?你夢想夢想你的親人死嗎?夢想有一個現實的影響和反應,還有夢想的主觀想像力,請參閱夢想世界夢想死亡的親屬的詳細解釋
夢想搶劫

夢想搶劫

夢想搶劫什麼意思?你夢想搶劫嗎?夢想著搶劫有一個現實的影響和反應,也有夢想的主觀想像力,請參閱週恭吉夢官方網站的詳細解釋。夢想搶劫
夢想缺乏缺乏紊亂

夢想缺乏缺乏紊亂

夢想缺乏缺乏紊亂什麼意思?你夢想缺乏異常藥物嗎?夢想缺乏現實世界的影響和現實,還有夢想的主觀想像,請看官方網站的夢想組織缺乏異常藥物。我覺得有些東西缺失了