作者:蔡瑋
中介軟體dble測試成員,主要負責dble的日常測試工作,熱衷於探索發現,學習新技術。
本文來源:原創投稿
*愛可生開源社群出品,原創內容未經授權不得隨意使用,轉載請聯絡小編並註明來源。
SSL協議簡介
眾所周知,如果我們在網路上傳輸資料時資訊都是使用明文的話,會很容易出現資料被監聽和竊取的情況,從而造成一定的安全性的問題,這對於一些個人敏感資訊乃至公司的資料安全無疑造成了很大的風險。
基於此,勢必有一定的需求,對網路上傳輸的資料進行“包裹化”處理,而SSL即在此背景之下應運而生。Netscape公司於1996年提出了安全協議SSL,其是工作於應用層和傳輸層之間的一款協議,設計即全面,其涉及的概念眾多,不僅僅“包裹化”資料【資料加密】,更是提供了身份驗證和訊息完整性驗證機制,為網路資料傳輸安全性建設做出了巨大貢獻,從而非常大程度上改善了網際網路的安全性問題。
對於資料庫層面,加密通訊同樣顯得很重要,畢竟任何業務的資料儲存最終都要落實到資料庫上,其重要性不言而喻。所以對於MySQL而言,SSL已經是一個成熟的功能並廣泛應用。對於協議實現原理以及加密演算法不再是本文介紹的重點,在此就不再贅述,可參考歷史公眾號文章:MySQL : SSL 連線淺析
SSL 之 DBLE 篇
概述
作為一款資料庫中介軟體產品,在使用 DBLE 時,將 MySQL 掛載到 DBLE 後端後,完全可以脫離 MySQL 而與 DBLE 進行直接建立連線。那麼問題來了,如何確保與 DBLE 進行通訊時資料的安全性呢?顯然,在這方面 DBLE 需要向 MySQL 學習,使用 SSL 武裝自己,以確保通訊時使用者資料的安全性。
在即將要發版的 DBLE 版本中,我們將會支援 SSL 加密連線,需要注意的是目前加密處理是處於 Client — DBLE 通訊階段,DBLE — MySQL 通訊階段暫未涉及。同時在已經發版的 DBLE 3.22.01.1 的小版本中也已率先支援了 SSL ,感興趣的同學可以下載相關的版本進行試用。
使用說明
對於 DBLE 的 SSL 連線配置和 MySQL 有一定的相似性,但是並不盡相同,下面就 DBLE 對於 SSL 加密的使用進行簡要的配置使用介紹。
熟悉 SSL 的同學應該知道,使用 SSL 的前提必然是各種證照【涉及各種金鑰資訊】,DBLE 也並不例外。MySQL 中使用的是自簽名證照,自簽名證照是由不受信的CA機構頒發的數字證照,也就是自己簽發的證照。與受信任的CA簽發的傳統數字證照不同,自簽名證照是由一些公司或軟體開發商建立、頒發和簽名的。DBLE 同樣採用和 MySQL 一樣的方式:使用自簽名證照方式製作 SSL 證照。
證照製作
證照製作需要藉助 OpenSSL 來進行,如果機器上並未安裝可手動進行安裝 OpenSSL 。
1、 製作CA自簽名證照(包含公鑰)和私鑰
openssl genrsa 2048 > ca-key.pem
openssl req -new -x509 -nodes -days 3600 -key ca-key.pem -out ca.pem
2、 建立私鑰和簽發服務端的數字證照
openssl req -newkey rsa:2048 -days 3600 -nodes -keyout server-key.pem -out server-req.pem
openssl rsa -in server-key.pem -out server-key.pem
openssl x509 -req -in server-req.pem -days 3600 -CA ca.pem -CAkey ca-key.pem -set_serial 01 -out server-cert.pem
3、建立私鑰和簽發客戶端的數字證照(與上相似)
openssl req -newkey rsa:2048 -days 3600 -nodes -keyout client-key.pem -out client-req.pem
openssl rsa -in client-key.pem -out client-key.pem
openssl x509 -req -in client-req.pem -days 3600 -CA ca.pem -CAkey ca-key.pem -set_serial 01 -out client-cert.pem
4、驗證服務端和客戶端數字證照是否可信,當輸出的結果為OK,表示通過
openssl verify -CAfile ca.pem server-cert.pem client-cert.pem
值得一提的是,MySQL 自帶一鍵生成證照的 mysql_ssl_rsa_setup 命令中內部也是大致按照以上生成證照的,所以更方便的做法是直接使用 mysql_ssl_rsa_setup 生成相應的證照檔案【當然用於 DBLE 處也需要再進行證照型別轉換,見下文】。
證照型別轉換
由於 DBLE 是基於 JAVA 語言進行開發的,OpenSSL 生成的證照格式 pem 、crt 等格式,在 JAVA 語言並不能正確識別,需要額外使用 keytool 工具【java 原生自帶,安裝 java 後不需要再進行安裝】轉換成 p12 、jks格式,同時如果使用的客戶端是 JDBC 時,相關的 URL 中用到的證照也需要使用格式轉換後的證照檔案,其他 Driver 則均適用於 pem 證照檔案。
1、將 ca.pem 匯入 Java 平臺的金鑰庫中,java 支援金鑰庫型別有:JKS 、JCEKS 、PKCS12 、PKCS11 和 DKS ,這裡生成 JKS 副檔名的 truststore.jks 金鑰庫,密碼可自定義,此處定義為123456
keytool -import -noprompt -file ca.pem -keystore truststore.jks -storepass 123456
2、將 server-cert.pem 和 server-key.pem 轉成 p12 型別的金鑰庫,然後在轉成 JKS 型別的金鑰庫,密碼可自定義,此處定義為123456
openssl pkcs12 -export -in server-cert.pem -inkey server-key.pem -out serverkeystore.p12 -passout pass:123456
keytool -importkeystore -srckeystore serverkeystore.p12 -srcstoretype PKCS12 -destkeystore serverkeystore.jks -srcstorepass 123456 -deststorepass 123456
3、同樣,將客戶端用到的證照檔案轉換為 JKS 型別的金鑰庫,密碼可自定義,此處定義為123456
openssl pkcs12 -export -in client-cert.pem -inkey client-key.pem -out clientkeystore.p12 -passout pass:123456
keytool -importkeystore -srckeystore clientkeystore.p12 -srcstoretype PKCS12 -destkeystore clientkeystore.jks -srcstorepass 123456 -deststorepass 123456
至此,我們一共得到了以下金鑰檔案資訊:
服務端DBLE配置
服務端 DBLE 配置
在使用 SSL 時,DBLE 作為服務端需要手動進行配置相關的檔案資訊,並開啟相關的功能。和 MySQL 一致,我們提供了一個開關 supportSSL ,用於標識SSL是否啟用,預設值為 false ,如果需要使用 SSL 連線時,首先需要確保此開關處於開啟的狀態。同時需要配置使用到的一些證照資訊,在 bootstrap.cnf 中進行如下配置:
-DsupportSSL=true
-DserverCertificateKeyStoreUrl=${path}/serverkeystore.jks
-DserverCertificateKeyStorePwd=123456
-DtrustCertificateKeyStoreUrl=${path}/truststore.jks
-DtrustCertificateKeyStorePwd=123456
配置完成之後,重啟 dble 即可。
為了便於查詢 SSL 的一些狀態資訊,我們在 DBLE 的管理端 dble_information 庫中新增了一些用於維護相關的 SSL 的後設資料資訊,確保配置無誤並重啟 dble 之後,可在 DBLE 管理端查詢到對應的 SSL 配置資訊以及狀態:
客戶端連線配置
在使用 SSL 連線 MySQL 時區分了多種連線模式,此方式同樣適用於 DBLE ,以下提供兩種常見的 Client 加密連線時的客戶端配置:
實驗
disabled模式
在使用 SSL 加密連線 DBLE 之前,讓我們先借助抓包工具 wireshark 來看看未使用加密連線 DBLE 時,資料傳輸是怎麼樣的。在這裡使用 JDBC 作為客戶端為例。在進行查詢之前,筆者已先行按照上述步驟在 DBLE 側配置並開啟了 SSL ,建立好了 user 表,並準備了相關的資料,在此不作為重點進行贅述。
1、非加密連線 DBLE ,以下為 JDBC Demo 可供參考,與 DBLE 建立連線並查詢 user 表資料:
public class SslTest {
private static final String JDBC_DRIVER = "com.mysql.jdbc.Driver";
public static void main(String[] args) throws SQLException, IOException, ClassNotFoundException {
List<User> res = disabled();
System.out.println(res);
}
public static List<User> disabled() throws ClassNotFoundException, IOException, SQLException {
List<User> usersList = new ArrayList<>();
Properties pro = new Properties();
FileInputStream fis = new FileInputStream("E:\\jdbc\\src\\main\\resources\\dble.properties");
pro.load(fis);
Class.forName(JDBC_DRIVER);
String url = "jdbc:mysql://" + pro.getProperty("host") + ":" + pro.getProperty("port") + "/" + pro.getProperty("db");
String fullUrlString = url + "?useSSL=false"; // 非加密連線
Connection conn = DriverManager.getConnection(fullUrlString, pro.getProperty("user"), pro.getProperty("password"));
PreparedStatement ps = conn.prepareStatement("select username from user");
ResultSet rs = ps.executeQuery();
while(rs.next()){
String name = rs.getString("username");
usersList.add(new User(name));
}
ps.close();
rs.close();
conn.close();
return usersList;
}
}
2、開啟抓包後,執行相關 demo 進行查詢,將資料包過濾、解析後如下所示:
可以發現,傳輸的資料包括登入資訊、SQL 以及返回的資料資訊,都是能夠透過 wireshark 經過解析後可以以明文的資訊查詢到。
required 模式
在此僅以某一種 SSL 加密模式為例進行測試演示——required ,在以上的 JDBC Demo 中稍加修改,將 URL 引數變更為相應的模式引數【如下所示】,即可進行加密通訊:
String fullUrlString = url
+ "?useSSL=true&requireSSL=true&verifyServerCertificate=false";
然後再次抓包並執行 Demo 進行查詢,解析資料包並過濾得到:
可以發現在建立 TCP 連線之後,SSL 協議隨之進行雙方的認證過程,具體協議分析可參考:https://www.jianshu.com/p/802... ,經過認證之後,隨即以 TLS 加密協議的標準將資料包進行加密後傳輸,即便經過初步的解析後也無法得到傳輸的資料資訊,最終確保了資料的安全性。當然,如果我們有服務端的 SSL 金鑰檔案,在 wireshark SSL 協議設定中新增相關的金鑰資訊,也是可以成功解析出傳輸的具體資料包資訊的,在此不再過多演示,感興趣的讀者可自行測試。
總結
凡事都有兩面性,加密連線雖然確保了資料的安全性,但是另一方面無疑是犧牲了部分效能。從 SSL 實現方式來看,建立連線時需要進行握手、加密、解密等操作。所以耗時基本都在建立連線的階段,這對於使用短連線的應用程式可能並不太友好,因為會產生較大的效能損耗。不過對於使用連線池或者長連線的應用程式可能會好許多。所以,對於要求高效能的應用,或者不產生核心敏感資料的應用,效能及可用性才是首要,建議不要採用 SSL 方式。
同時需要注意區別的是,DBLE 側在進行 SSL 設定時,並沒有像 MySQL 一樣設定了【require_secure_transport】 類似的強制要求使用安全連線引數設定,也沒有按照使用者去區分 SSL 配置的適用物件,只要 DBLE 服務端開啟並正確配置了 SSL 選項,所有使用者與 DBLE 建立連線時均可自主選擇是否需要採用 SSL 加密連線。