企業最寶貴的資產往往儲存在資料庫:客戶隱私、財務帳目、知識產權。MySQL 作為最流行的開源資料庫,其安全防護不僅是 DBA 責任,更是全組織的合規底線。本文構建 **「配置加固 → 存取控制 → 傳輸加密 → 審計監控 → 事件響應」** 五層纵深防禦體系。
-- 刪除匿名用戶
DELETE FROM mysql.user WHERE User = '';
-- 禁止 root 遠程登入
DELETE FROM mysql.user WHERE User = 'root' AND Host NOT IN ('localhost', '127.0.0.1', '::1');
-- 刪除測試庫
DROP DATABASE IF EXISTS test;
DELETE FROM mysql.db WHERE Db = 'test' OR Db = 'test\\_%';
FLUSH PRIVILEGES;
執行 mysql_secure_installation 互動腳本可一鍵完成上述操作。
[mysqld]
-- 強制密碼驗證插件 (8.0+ 預設 caching_sha2_password)
default_authentication_plugin = caching_sha2_password
-- 密碼複雜度 (需安裝 validate_password 插件)
validate_password.length = 14
validate_password.mixed_case_count = 1
validate_password.number_count = 1
validate_password.special_char_count = 1
validate_password.policy = STRONG
定期輪換密碼,禁止共用帳號,根帳號僅限 DBA 緊急使用,應用使用專用低權限帳號。
[mysqld]
local_infile = OFF -- 禁用 LOAD DATA LOCAL INFILE (防任意檔案讀取)
secure_file_priv = /var/lib/mysql-files/ -- 限制 SELECT ... INTO OUTFILE/LOAD DATA 目錄
skip_show_database -- 非 SUPER 權限用戶隱藏 SHOW DATABASES
skip_symbolic_links -- 禁用符號連結 (防目錄遍歷)
-- 禁用舊版不安全認證
old_passwords = 0
bind-address = 192.168.1.100 (內網 IP),拒絕公網直接訪問。skip_networking + Unix Socket (socket=/var/run/mysqld/mysqld.sock)。-- 建立角色
CREATE ROLE 'app_read', 'app_write', 'app_admin';
GRANT SELECT ON mydb.* TO 'app_read';
GRANT SELECT, INSERT, UPDATE, DELETE ON mydb.* TO 'app_write';
GRANT ALL PRIVILEGES ON mydb.* TO 'app_admin';
-- 建立用戶並授予角色
CREATE USER 'api_svc'@'10.0.%' IDENTIFIED BY 'strong_password';
GRANT 'app_write' TO 'api_svc'@'10.0.%';
SET DEFAULT ROLE 'app_write' TO 'api_svc'@'10.0.%';
GRANT SELECT (id, username, email) ON mydb.users TO 'api_svc'@'10.0.%'; -- 隱藏 password_hash, salt
GRANT SELECT (id, order_no, amount) ON mydb.orders TO 'report_svc'@'10.0.%';
錯誤: GRANT ALL ON *.* TO 'user'@'%';
正確: 具體到庫、表、列、主機。定期審計:SHOW GRANTS FOR 'user'@'host';
[mysqld]
require_secure_transport = ON -- 強制所有連線使用 SSL
ssl_ca = /etc/mysql/ssl/ca.pem
ssl_cert = /etc/mysql/ssl/server-cert.pem
ssl_key = /etc/mysql/ssl/server-key.pem
客戶端驗證伺服器憑證 (防中間人):
-- 連線字串
SslMode=VerifyFull;SslCa=/path/to/ca.pem; -- .NET (MySqlConnector)
-- 或
sslmode=VERIFY_CA sslrootcert=/path/to/ca.pem # libpq / JDBC
# 本地建立隧道
ssh -L 3307:db-server:3306 user@bastion-host
# 應用連線 127.0.0.1:3307 實際通往 db-server:3306,流量經 SSH 加密
[mysqld]
general_log = ON
general_log_file = /var/log/mysql/general.log
log_output = FILE
記錄所有連線、查詢,影響效能,**僅審計期間啟用**。
INSTALL PLUGIN audit_log SONAME 'audit_log.so';
-- 配置
audit_log_policy = ALL; -- 記錄所有操作
audit_log_format = JSON; -- 結構化日誌
audit_log_file = /var/log/mysql/audit.log;
audit_log_rotate_on_size = 100M;
audit_log_rotations = 10;
日誌包含:用戶、IP、SQL 文本、影響行數、執行耗時、錯誤碼,支援 SIEM 接入。
slow_query_log = ON
slow_query_log_file = /var/log/mysql/slow.log
long_query_time = 1
log_queries_not_using_indexes = ON
log_error = /var/log/mysql/error.log
log_warnings = 2
CREATE TABLE audit_ddl (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
event_time TIMESTAMP(3) DEFAULT CURRENT_TIMESTAMP(3),
user_host VARCHAR(100),
db_name VARCHAR(64),
object_type VARCHAR(20),
object_name VARCHAR(64),
sql_text TEXT
);
CREATE TRIGGER trg_audit_ddl AFTER DDL ON DATABASE
FOR EACH STATEMENT
BEGIN
INSERT INTO audit_ddl (user_host, db_name, object_type, object_name, sql_text)
VALUES (CURRENT_USER(), DATABASE(), EVENT_OBJECT_TYPE(), EVENT_OBJECT_NAME(), EVENT_SQL());
END;
mysqldump --single-transaction --routines --triggers --events --master-data=2 --flush-logs --hex-blob (一致性快照)。openssl enc -aes-256-gcm 加密備份檔,金鑰分離保管。REVOKE ALL ON *.* FROM 'compromised'@'%';。mysqlbinlog)、審計日誌、錯誤日誌、作業系統日誌。| 要求 | MySQL 實現 |
|---|---|
| 資料最小化/目的限制 | 列級權限、視圖遮罩、虛擬欄位加密 |
| 傳輸/靜態加密 | TLS 1.2+、TDE (Tablespace Encryption 8.0+)、應用層字段加密 |
| 存取控制與審計 | 角色權限、審計插件、觸發器審計、Binlog 解析 |
| 資料保留與刪除 | 分區表自動清理、GDPR 刪除 API、Binlog 保留策略 |
| 事件通報 (72小時) | 審計日誌告警、SIEM 關聯分析、應急預案演練 |
MySQL 安全不是裝個插件、改個配置就能一勞永逸的。它需要:**基線配置自動化 (Ansible/Terraform)、權限定期審計 (季度)、補丁管理 (關注 CVE)、審計日誌集中分析 (ELK/Splunk)、備份恢複原演練 (半年)、紅藍隊演練 (年度)**。將安全內化為 DevSecOps 流程一環,才能真正守住資料底線。