資料庫安全是系統防線的最後一道關卡。MySQL 官方文檔提煉的 23 條安全建議,涵蓋網路傳輸、認證授權、權限最小化、審計監控、參數硬化等全維度。本文重新組織並深度解析這 23 條鐵律,構建可落地的 MySQL 安全防護體系。
生產環境跨 VPC/公網/IDC 連線,強制使用 SSH 隧道 或 SSL/TLS 加密:
# SSH 隧道範例(本地 3307 轉發至遠端 3306)
ssh -L 3307:localhost:3306 user@db-server -N
# MySQL 客戶端啟用 SSL
mysql -h 127.0.0.1 -P 3307 -u app_user -p --ssl-mode=REQUIRED
MySQL 5.7+ 預設支援 SSL,需配置 ssl-ca、ssl-cert、ssl-key 並啟用 require_secure_transport=ON。
# 外部視角掃描
nmap -p 3306
# 或簡易測試
telnet 3306
# 如能連通 → 立即整改防火牆規則
-- 登入
mysql -u root -p
-- 修改(5.7.6+ 推薦 ALTER USER)
ALTER USER 'root'@'localhost' IDENTIFIED BY 'new_strong_password';
-- 或舊版相容
SET PASSWORD FOR 'root'@'localhost' = PASSWORD('new_strong_password');
-- 生效
FLUSH PRIVILEGES;
DELETE FROM mysql.user WHERE User='';DELETE FROM mysql.user WHERE User='root' AND Host!='localhost';-- 僅授予特定庫、特定表、特定操作
GRANT SELECT, INSERT, UPDATE ON `mall_order`.* TO 'app_order'@'10.0.1.%' IDENTIFIED BY 'strong_pass';
-- 撤銷多餘權限
REVOKE DELETE ON `mall_order`.* FROM 'app_order'@'10.0.1.%';
bcrypt/argon2/PBKDF2(非 MD5/SHA1)mysql.user 使用 caching_sha2_password (8.0 預設) 或 mysql_native_password[mysqld]
validate_password_policy=STRONG
validate_password_length=16
validate_password_mixed_case_count=1
validate_password_number_count=1
validate_password_special_char_count=1
| 應用角色 | 建議權限 | 禁止權限 |
|---|---|---|
| 唯讀報表 | SELECT | INSERT/UPDATE/DELETE/DROP/ALTER |
| 寫入服務 | SELECT, INSERT, UPDATE | DROP/ALTER/GRANT/FILE |
| 遷移/ETL | SELECT, INSERT, UPDATE, DELETE | DROP/ALTER/GRANT/SHUTDOWN |
| 管理員 | ALL PRIVILEGES (受限主機) | -- |
PROCESS 可見所有執行中 SQL(含敏感參數)SUPER 可 KILL 連線、修改全域變數、控制複寫-- 危險範例:讀取系統密碼檔
LOAD DATA INFILE '/etc/passwd' INTO TABLE temp;
SELECT * FROM temp;
生產庫嚴禁授予 FILE 給非 DBA 帳號。
-- 全域限制
SET GLOBAL max_user_connections = 100;
-- 特定帳號限制 (需 SUPER 權限)
GRANT USAGE ON *.* TO 'app_user'@'%' WITH MAX_USER_CONNECTIONS 50;
GRANT USAGE ON *.* TO 'app_user'@'%'
WITH MAX_QUERIES_PER_HOUR 10000
MAX_UPDATES_PER_HOUR 5000
MAX_CONNECTIONS_PER_HOUR 2000
MAX_USER_CONNECTIONS 50;
-- ❌ 錯誤:字串拼接
"SELECT * FROM users WHERE id = " + input_id
-- ✅ 正確:預處理參數綁定
PreparedStatement ps = conn.prepareStatement("SELECT * FROM users WHERE id = ?");
ps.setInt(1, input_id);
所有語言驅動(JDBC、PDO、MySQLdb、Go database/sql)均支援預處理,**嚴禁手動拼接 SQL**。
VARCHAR(32)、TINYINT UNSIGNED)、CHECK 約束 (8.0.16+)| 語言/驅動 | 跳脫函數 | |
|---|---|---|
| PHP (PDO) | $pdo->quote() / 預處理 | |
| Java (JDBC) | PreparedStatement | |
| Python (MySQLdb/PyMySQL) | cursor.execute(%s, params) | |
| Go (database/sql) | db.Query(sql, args...) | |
| C/C++ | mysql_real_escape_string() |
| 參數 | 建議值 | 效果 |
|---|---|---|
| local_infile | 0 | 禁用 LOAD DATA LOCAL(防止客戶端任意讀檔) |
| skip_grant_tables | 關閉 (預設) | 啟用則繞過所有權限檢查,**極度危險** |
| skip_show_database | ON | 隱藏 SHOW DATABASES(非 DBA 不需知庫清單) |
# 1. 停止服務
systemctl stop mysqld
# 2. 跳過授權表啟動
mysqld_safe --skip-grant-tables --skip-networking &
# 3. 無密碼登入重設
mysql -u root mysql
UPDATE user SET authentication_string=PASSWORD('new_strong_pass') WHERE User='root';
FLUSH PRIVILEGES;
# 4. 正常重啟
systemctl restart mysqld
⚠️ --skip-networking 防止跳過授權期間外部連線入侵。
mysql_secure_installation、Lynis、CIS Benchmark 檢查SHOW GRANTS 全帳號審視,收回過期/過度權限audit_log 外掛記錄所有 DDL/DML/登入/失敗嘗試安全非一次性配置,而是持續的**最小權限、加密傳輸、審計可追溯、快速應急響應**四大支柱建設。