首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫

MySQL 數據庫安全配置實戰:從目錄權限到編程防注入的纵深加固指南

     編輯:MySQL 資料庫相關知識

前言:MySQL 安全 = 主機安全 + 配置安全 + 編程安全

默認安裝面向兼容性,生產環境必須進行針對性加固。本文實戰記錄 **數據目錄權限演進 (3.21→3.23)、運行用戶隔離、授權表最小權限、本地日志洩露防範、編程層參數化查詢、語言特定防注入 API** 全鏈路加固清單。

一、數據目錄權限演進史與最佳實踐

版本數據目錄權限風險現代標準
3.21.x775 (rwxrwxr-x)任意本地用戶可讀,拷貝 .MYD/.MYI/.frm 直讀數據700 (rwx------)
擁有者 = mysql 用戶
組 = mysql 組
3.22.x770 (rwxrwx---)同組用戶可讀寫,仍不安全
3.23+700 (rwx------)僅 mysql 用戶可訪問,基準安全

生產環境檢查清單:


# 1. 確認運行用戶
ps -eo user,cmd | grep mysqld | grep -v grep
# 應為 mysql (或專用用戶),絕非 root

# 2. 修正目錄權限
chown -R mysql:mysql /var/lib/mysql
chmod 700 /var/lib/mysql
find /var/lib/mysql -type f -exec chmod 600 {} \;

# 3. 配置文件權限
chown root:mysql /etc/my.cnf
chmod 640 /etc/my.cnf

# 4. 日志文件權限
chown mysql:mysql /var/log/mysqld.log /var/log/mysql/*
chmod 640 /var/log/mysqld.log /var/log/mysql/*

二、授權表最小權限模型實戰

2.1 清理默認不安全帳號


-- 登錄 root 執行
DELETE FROM mysql.user WHERE User = '';                    -- 匿名用戶
DELETE FROM mysql.user WHERE User = 'root' AND Host != 'localhost'; -- 非本地 root
DROP DATABASE IF EXISTS test;
DELETE FROM mysql.db WHERE Db = 'test' OR Db = 'test\_%';
FLUSH PRIVILEGES;

2.2 業務帳號權限模板

角色權限授予語句Host 限制
Web 應用讀寫GRANT SELECT, INSERT, UPDATE, DELETE ON app_db.* TO 'app_rw'@'10.0.1.%' IDENTIFIED BY 'StrongP@ssw0rd';應用服務器段
Web 應用只讀GRANT SELECT ON app_db.* TO 'app_ro'@'10.0.1.%' IDENTIFIED BY 'StrongP@ssw0rd';應用服務器段
備份帳號GRANT SELECT, LOCK TABLES, SHOW VIEW, EVENT, TRIGGER, RELOAD, PROCESS ON *.* TO 'backup'@'10.0.2.10' IDENTIFIED BY 'StrongP@ssw0rd';備份服務器 IP
監控帳號GRANT PROCESS, REPLICATION CLIENT, SELECT ON performance_schema.* TO 'monitor'@'10.0.3.%' IDENTIFIED BY 'StrongP@ssw0rd';監控系統段
DBA 管理GRANT ALL PRIVILEGES ON *.* TO 'dba'@'10.0.0.5' IDENTIFIED BY 'StrongP@ssw0rd' WITH GRANT OPTION;堡壘機/管理 IP

原則:Host 盡量具體到 IP/段,禁用 '%';權限按「最小完成任務」授予;定期 SHOW GRANTS 審計。

三、危險權限「零授權」清單

權限風險場景策略
FILESELECT ... INTO OUTFILE '/var/www/html/shell.php' 寫 Webshell;LOAD DATA INFILE '/etc/passwd' 讀敏感文件僅 DBA/備份按需授予,且設置 secure_file_priv=/var/lib/mysql-files/
PROCESSSHOW FULL PROCESSLIST 看到含密碼的 SQL (如 SET PASSWORD、INSERT ... VALUES('pwd'))僅監控/管理帳號
SUPERKILL 任意線程、修改全局變量、CHANGE MASTER、啟用一般日志寫 Webshell極度收緊,僅 DBA
SHUTDOWN遠程關閉數據庫服務禁用
CREATE USER / GRANT OPTION權限提升、橫向移動僅 DBA

四、本地日志洩露防範:.bash_history / .mysql_history

風險:命令行帶密碼 mysqldump -uroot -pP@ssw0rd db > dump.sql 寫入 .bash_history;SQL 交互修改密碼 SET PASSWORD = PASSWORD('new') 寫入 .mysql_history。

4.1 即時清理與永久禁用


# 當前用戶
rm -f ~/.bash_history ~/.mysql_history
ln -s /dev/null ~/.bash_history
ln -s /dev/null ~/.mysql_history

# 系統級 (所有用戶生效,需 root)
echo 'unset HISTFILE' >> /etc/profile
echo 'export MYSQL_HISTFILE=/dev/null' >> /etc/profile
# 或在用戶 .bashrc / .bash_profile 設置

4.2 操作規範:絕不在命令行明文密碼


# 錯誤示範
mysqldump -uroot -pP@ssw0rd db > dump.sql
mysql -uroot -pP@ssw0rd -e "UPDATE user SET password=PASSWORD('new')"

# 正確姿勢
mysqldump -uroot -p db > dump.sql   # 交互輸入密碼
mysql -uroot -p -e "SET PASSWORD = PASSWORD('new')"  # 交互輸入
# 或使用配置文件
[client]
user=root
password="P@ssw0rd"  # 文件 600 權限
# mysqldump --defaults-file=/etc/mysql/backup.cnf db > dump.sql

五、編程層防注入:各語言標準 API 對照表

語言/框架標準防注入 API核心原理禁用/危險用法
PHPPDO::prepare() / mysqli_prepare()服務端預處理 (emulate=false),參數與代碼分離字符串拼接、mysqli_real_escape_string (僅作兼容)
JavaPreparedStatement / JPA @Query / MyBatis #{}JDBC 預處理 / ORM 參數綁定Statement + 拼接、${} (MyBatis 原生 SQL)
Pythoncursor.execute(sql, params) / SQLAlchemy text()DB-API 參數化 / ORM 編譯cursor.execute(sql % params)、f-string 拼接
Godb.Prepare() / sqlx.NamedExec()database/sql 預處理fmt.Sprintf 拼接
C#/.NETSqlCommand.Parameters.Add() / EF Core FromSqlInterpolatedADO.NET 參數化 / EF 參數化String.Concat/Interpolation 直接拼接
Node.jsmysql2/promise pool.execute() / Sequelize/Prisma/TypeORM預處理 / ORM 參數化connection.query(sql + val)、模板字符串拼接
PerlDBI prepare/execute / DBIx::ClassDBI 參數化do() 拼接、quote() 僅作備選
C/C++mysql_stmt_prepare() / MySQL++ quote/escapeC API 預處理 / 封裝庫參數化sprintf 拼接、mysql_real_escape_string() 單獨使用

六、Web 應用通用輸入驗證白名單規範


# 正則白名單示例 (PHP)
function validate($input, $type) {
    $patterns = [
        'int'    => '^\d+$',
        'uint'   => '^[1-9]\d*$',
        'email'  => '^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$',
        'alpha'  => '^[a-zA-Z]{1,50}$',
        'alnum'  => '^[a-zA-Z0-9]{1,50}$',
        'safe'   => '^[a-zA-Z0-9_\-\.@]{1,100}$',  // 通用安全字符
        'date'   => '^\d{4}-\d{2}-\d{2}$',
        'datetime'=> '^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}$',
    ];
    return isset($patterns[$type]) && preg_match('/'.$patterns[$type].'/', $input);
}

# 使用
$id = $_GET['id'] ?? '';
if (!validate($id, 'uint')) { http_response_code(400); exit('Invalid ID'); }
$stmt = $pdo->prepare("SELECT * FROM users WHERE id = ?");
$stmt->execute([$id]);

七、網絡與審計:最後一道防線

  1. 網絡微隔離:安全組/防火牆僅放行應用服務器 IP → 3306;禁用公網訪問;管理走堡壘機/VPN/SSH 隧道。
  2. 審計日志:MariaDB/MySQL Enterprise Audit / McAfee Audit Plugin / pgaudit (PG) 記錄:登錄、DDL、DML、失敗嘗試、敏感表訪問。
  3. 加密傳輸:REQUIRE SSL 用戶、require_secure_transport=ON、skip_name_resolve=ON。
  4. 定期滲透測試:SQLMap、自定義腳本、紅隊演練,驗證防禦有效性。

結語

MySQL 安全加固無銀彈,**目錄權限 700 + 專用運行用戶 + 最小權限帳號 + 禁用危險權限 + 參數化查詢 + 日志不洩露 + 網絡微隔離 + 審計可追溯**,九層防線缺一不可。將上述清單固化為 Ansible Playbook / Terraform Module / Dockerfile 最佳實踐,納入 CI/CD 門禁與定期巡檢,方能構建經得起實戰考驗的數據庫安全基線。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved