遠端訪問Mysql?教你為資料傳輸再加把安全鎖!
線上業務為了保證資料安全,一般只允許本地或者內網訪問MySQL。但一些特殊情況下,需要通過外網訪問MySQL。此時為了保證許可權最小化開放,首先要做兩方面措施:
一方面需要配置防火牆白名單
iptables -A INPUT -s 1.2.3.4 -p tcp -m tcp –dport 3306 -j ACCEPT
另一方面建立MySQL使用者時限制訪問IP
mysql> CREATE USER ‘testuser’@’1.2.3.4’ IDENTIFIED BY ‘testpass’;
那麼,做到這一步就可以高枕無憂了嗎?如果是的話,文章到此就可以結束了。但是很遺憾,實際上仍然存在安全隱患。MySQL的訪問預設是明文的,與明文的HTTP的容易受到監聽、劫持類似,暴露在外網的MySQL通訊也有可能受到監聽、中間人攻擊等。下面以一個具體例子進行說明。
1 監聽MySQL主從的明文通訊
實現監聽的方案有多種,我們採用了交換機埠映象的方式進行旁路監聽。
準備監聽的機器為xxx.xxx.xxx.83,發起攻擊的機器為xxx.xxx.xxx.109。
實施MySQL主從通訊的監聽時, 無論是監聽主庫還是從庫效果都類似,這裡測試監聽主庫的情況。
1.1 確定要監聽的埠
如果不知道這兩臺機器對應交換機哪個埠,可以先登入交換機,ping然後通過arp快取檢視。
ping之後就能通過arp快取確定埠
最後,確定xxx.xxx.xxx.83即映象源埠為g0/15,xxx.xxx.xxx.109即映象目標埠為g0/1。
1.2 配置埠映象
登入交換機,開始沒有配置映象
<H3C>dis mir
The monitor port has not been configured! <H3C>sys
Password: ************
Enter system view, return to user view with Ctrl+Z.
分別配置映象目標和映象源埠
[H3C]monitor-port g0/1 Succeed! the monitor port has been specified to be Trunk port and the pvid changed. [H3C]mirroring-port g0/15 [H3C] [H3C]dis mir Monitor-port: GigabitEthernet0/1 Mirroring-port: GigabitEthernet0/15 [H3C]q <H3C>save This will save the configuration in the EEPROM memory Are you sure?[Y/N]y Now saving current configuration to EEPROM memory Please wait for a while... Current configuration saved to EEPROM memory successfully
1.3 監聽明文的主從通訊
在主動監聽的機器xxx.xxx.xxx.109執行
tcpdump host xxx.xxx.xxx.83 -i eth0 -w hello.dump
xxx.xxx.xxx.83配置了MySQL主庫,另外的一臺外網機器xxx.xxx.xxx.104配置了MySQL從庫。並且該主從並未配置SSL加密。測試中利用xxx.xxx.xxx.109成功監聽到MySQL主從的通訊。
下圖為監聽到的MySQL帳號登入,可以得到使用者名稱和加密後的密碼:
對於不復雜的MySQL密碼,可以很容易通過cmd5等網站解密出明文:
下圖為監聽到的主從資料:
可以看到,在MySQL主從明文通訊的情況下,可以實現有效的竊聽。
這裡採用的交換機埠映象需要獲得交換機許可權,有一定的實施難度。但在外網通訊中,實際的網路環境非常複雜且不受我們控制,明文通訊仍然有潛在的安全風險。
2 伺服器間安全訪問
那麼如何在伺服器之間的外網通訊中確保MySQL的安全訪問呢?這裡介紹幾種常用方案。
2.1 加密隧道
加密隧道可以將客戶端的網路資料進行加密,然後安全地傳輸到服務端後進行解密還原。以stunnel為例:
首先在客戶端監聽3306埠,並建立加密通訊,連線到遠端的1.2.4.5:8000
/usr/local/stunnel/etc/stunnelclient.conf
sslVersion = TLSv1
CAfile = /usr/local/stunnel/etc/ca-cert.pem
cert = /usr/local/stunnel/etc/clientcert.pem
key = /usr/local/stunnel/etc/clientkey.pem
[mysql]
accept = 127.0.0.1:3306
connect =1.2.4.5:8000
服務端監聽8000埠,並將資料解密後轉發到本機的3306埠
/usr/local/stunnel/etc/stunnelserver.conf
sslVersion = TLSv1
CAfile = /usr/local/stunnel/etc/ca-cert.pem
cert = /usr/local/stunnel/etc/servercert.pem
key = /usr/local/stunnel/etc/serverkey.pem
[mysql]
accept=8000
connect=127.0.0.1:3306
這樣,客戶端訪問本地3306埠實際會訪問到遠端1.2.4.5機器的3306埠,實現了通過加密隧道訪問遠端的MySQL。
優點:無需單獨建立外網的MySQL帳號,對本地訪問透明。
缺點:只能實現從客戶端到服務端的加密訪問,需要額外維護加密隧道服務。
2.2 VPN
VPN可以將外網通訊轉化為虛擬的內網通訊,直接解決外網訪問的安全問題。以OPENVPN為例:
在其中一邊的伺服器搭建服務端,配置內網網段
/etc/openvpn/server.conf
port 1194
proto tcp-server
dev tap
#證書相關
ca /etc/openvpn/ca-cert.pem
cert /etc/openvpn/server.pem
key /etc/openvpn/server.key
dh /etc/openvpn/dh.pem
#指定Server端使用的地址
ifconfig 192.168.10.1 255.255.255.0
#指定客戶端的IP
client-config-dir /etc/openvpn/ccd
在另一邊的伺服器搭建客戶端,發起VPN連結
/etc/openvpn/client.conf
client
dev tap
proto tcp-client
remote 1.2.3.4 1194
#證書相關
ca /etc/openvpn/ca-cert.pem
cert /etc/openvpn/client1-cert.pem
key /etc/openvpn/client1-key.pem
這樣,兩邊的伺服器就建立起虛擬的內網,可以訪問相互的MySQL或者其他服務。
優點:兩邊都可以相互訪問,且不限於訪問某個埠,特別適合異地機房間的內網互通。
缺點:需要額外維護VPN服務。
2.3 MySQL SSL
除了建立加密隧道、加密虛擬網路,還可以直接使用SSL進行MySQL的訪問加密。
2.3.1 SSL證書的生成
首先檢查MySQL是否支援SSL。
mysql> SHOW VARIABLES LIKE ‘have_ssl’;
+—————+———-+ | Variable_name | Value
| +—————+———-+ | have_ssl | DISABLED |
+—————+———-+ 1 row in set (0.00 sec)
如果輸出如上,說明MySQL支援SSL但未啟用。
SSL證書分多種型別,實際中要根據不同用途來使用服務端或客戶端的證書。
[mysqld]
# 服務端型別SSL證書,用於服務端,或者主從關係中的主庫
ssl-ca=/home/mysql/certs/ca-cert.pem ssl-cert=/home/mysql/certs/server-cert.pem
ssl-key=/home/mysql/certs/server-key.pem
[client]
# 客戶端型別SSL證書,用於客戶端(如命令列工具),或者主從關係中的從庫
ssl-ca=/home/mysql/certs/ca-cert.pem
ssl-cert=/home/mysql/certs/client-cert.pem
ssl-key=/home/mysql/certs/client-key.pem
此外,為了方便統一管理,在同一臺機器可以使用同時支援服務端和客戶端型別的單一SSL證書。只需要生成SSL證書時指定兩種型別的用法或者直接不指定任一種用法。
配置完畢後,檢查下SSL是否已啟用
mysql> SHOW VARIABLES LIKE ‘%ssl%’;
+—————+———————–+
| Variable_name | Value |
+—————+———————–+
| have_openssl | YES |
| have_ssl | YES |
| ssl_ca | /home/mysql/certs/ca-cert.pem |
| ssl_capath | |
| ssl_cert | /home/mysql/certs/mysql-cert.pem |
| ssl_cipher | |
| ssl_key | /home/mysql/certs/mysql-key.pem |
+—————+———————–+
5 rows in set (0.00 sec)
如果輸出如上,說明SSL已正常啟用
2.3.2 require SSL與require X509
為了確保外網訪問的MySQL使用者使用了SSL加密,在生成使用者時可以強制要求REQUIRE SSL或REQUIRE X509:
mysql> CREATE USER ‘testuser’@’1.2.3.4’ IDENTIFIED BY ‘testpass’ REQUIRE SSL;
mysql> CREATE USER ‘testuser’@’1.2.3.4’ IDENTIFIED BY ‘testpass’ REQUIRE X509;
兩者的區別在於,REQUIRE SSL只要求客戶端使用指定ca證書對服務端證書進行驗證,而REQUIRE X509還要求服務端對客戶端證書進行驗證。為了避免中間人攻擊,確保更安全的通訊,一般建議使用REQUIRE X509。
2.3.3 OpenSSL與yaSSL
MySQL可以使用自帶的yaSSL庫進行加密通訊,也可以使用OpenSSL進行加密通訊。具體使用哪種,需要在編譯時指定WITH_SSL:STRING的引數:
bundled (use yassl), yes (prefer os library if present, otherwise use bundled), system
(use os library), </path/to/custom/installation>
為了更好的安全性,可以使用系統自帶的OpenSSL,並及時做好yum/apt更新。
如果考慮不同版本的相容性,那麼建議使用自帶的yaSSL。
比如OpenSSL曾針對CVE-2015-4000的漏洞將DH key的最小值提高到768 bits,而一些舊版本MySQL的DH key使用了512 bits。因為MySQL的預設SSL加密演算法是DHE-RSA-AES256-SHA,如果使用了OpenSSL的MySQL,在不同版本間的訪問可能會出現ERROR 2026的錯誤提示。
2.3.4 監聽基於SSL的主從通訊
配置了SSL加密之後,我們再次嘗試抓取MySQL主從通訊。
發現無法獲取到MySQL主從的登入帳號:
此外擷取到的MySQL主從資料也是亂碼:
可以看到,在MySQL主從經過SSL加密的情況下,無法實現有效竊聽。
3 本地安全訪問
3.1 SSH隧道
一般我們都需要SSH方式從本地訪問遠端伺服器,這時可以建立SSH隧道來訪問遠端伺服器的特定埠。
如使用SecureCRT的埠轉發功能(Putty也類似),將本地3306埠轉發到伺服器的3306埠:
如果習慣使用navicat這類工具,可以使用自帶的SSH隧道功能(注意舊版可能要將私鑰轉換成ppk格式):
3.2 phpmyadmin+HTTPS
如果習慣使用phpmyadmin的web方式訪問MySQL,那麼只需要將訪問方式統一為HTTPS:
server
{
listen 80;
server_name phpmyadmin.example.com;
#使用HSTS強制把HTTP跳轉到HTTPS
add_header Strict-Transport-Security “max-age=31536000 “;
……
}server
{
listen 443 ssl http2;
server_name phpmyadmin.example.com;
#配置服務端SSL證書
ssl on;
ssl_certificate /etc/letsencrypt/live/phpmyadmin.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/ phpmyadmin.example.com/privkey.pem;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
……
}
4 總結
MySQL的資料安全是一個非常大的課題,其中外網間的安全通訊往往容易被忽略。而當前隨著HTTPS /SMTPS/POP3S/IMAPS的逐步流行,各種基於TCP、UDP的加密通訊方案也會越來越多地應用到線上業務中。本文針對伺服器間/本地到伺服器的一些訪問MySQL的場景介紹了幾種加密通訊方案,希望能給到大家一些思路,並結合自己實際需要來使用MySQL的加密訪問。
文章來自微信公眾號:運維軍團