安全加固
TLS、最小权限、审计、加密表空间、动态脱敏——把 MariaDB 安全做到位
最小权限模板
应用账号
CREATE USER 'app'@'10.%' IDENTIFIED BY 'strong-random-32-char';
GRANT SELECT, INSERT, UPDATE, DELETE ON app.* TO 'app'@'10.%';
-- 不给 DROP / ALTER / GRANT / SUPER只读账号(给 BI / AI / 报表)
CREATE USER 'readonly'@'%' IDENTIFIED BY 'xxx';
GRANT SELECT ON app.* TO 'readonly'@'%';
-- 也可以加 SHOW VIEW备份账号
CREATE USER 'backup'@'localhost' IDENTIFIED BY 'xxx';
GRANT RELOAD, LOCK TABLES, PROCESS, REPLICATION CLIENT, SHOW VIEW, EVENT, TRIGGER ON *.* TO 'backup'@'localhost';
GRANT BACKUP_ADMIN ON *.* TO 'backup'@'localhost';DBA 账号(按需用)
CREATE USER 'dba'@'10.0.0.5' IDENTIFIED BY 'xxx';
GRANT ALL PRIVILEGES ON *.* TO 'dba'@'10.0.0.5' WITH GRANT OPTION;只给特定 IP,不给 %。
监控账号
CREATE USER 'exporter'@'localhost' IDENTIFIED BY 'xxx';
GRANT PROCESS, REPLICATION CLIENT, SELECT ON performance_schema.* TO 'exporter'@'localhost';
GRANT SLAVE MONITOR ON *.* TO 'exporter'@'localhost';Audit AI 账号
CREATE USER 'ai_audit'@'%' IDENTIFIED BY 'xxx';
GRANT SELECT, INSERT ON audit.* TO 'ai_audit'@'%';详见 MCP Server 实战。
TLS
强制客户端用 TLS:
ALTER USER 'app'@'10.%' REQUIRE SSL;服务端配置:
[mariadb]
ssl_ca = /etc/ssl/mysql/ca.pem
ssl_cert = /etc/ssl/mysql/server-cert.pem
ssl_key = /etc/ssl/mysql/server-key.pem
require_secure_transport = ON验证:
SHOW STATUS LIKE 'Ssl_cipher';
-- 输出非空就是 TLS 连接客户端:
mysql -h host -u app -p --ssl --ssl-ca=/path/to/ca.pem或在 URI 加 ?sslmode=required。
自动签发证书
# 生成 CA
openssl genrsa 4096 > ca.key
openssl req -x509 -days 3650 -nodes -key ca.key -out ca.pem -subj "/CN=MariaDB CA"
# server cert
openssl req -newkey rsa:2048 -nodes -keyout server.key -out server.csr -subj "/CN=db.example.com"
openssl x509 -req -days 365 -in server.csr -CA ca.pem -CAkey ca.key -CAcreateserial -out server.pem审计
服务端审计插件
INSTALL SONAME 'server_audit';
SET GLOBAL server_audit_logging = ON;
SET GLOBAL server_audit_events = 'CONNECT,QUERY_DDL,QUERY_DML,QUERY_DCL';
SET GLOBAL server_audit_file_path = '/var/log/mariadb/audit.log';
SET GLOBAL server_audit_file_rotate_size = 100M;
SET GLOBAL server_audit_file_rotations = 100;输出格式:
20260518 12:00:00,host,app,10.0.0.5,123,12345,QUERY,app,'SELECT * FROM users',0general_log(调试用,勿生产)
SET GLOBAL general_log = ON;
SET GLOBAL general_log_file = '/var/log/mariadb/general.log';性能开销大,只在排查时用。
慢查询日志
slow_query_log = 1
slow_query_log_file = /var/log/mariadb/slow.log
long_query_time = 0.5
log_queries_not_using_indexes = 1配合 pt-query-digest 分析。
加密
加密表空间(at-rest)
[mariadb]
plugin_load_add = file_key_management
file_key_management_filename = /etc/mysql/keyfile
file_key_management_encryption_algorithm = AES_CTR
innodb_encrypt_tables = ON
innodb_encrypt_log = ON
innodb_encryption_threads = 4keyfile 格式:
1;DEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEF
2;BEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADkeyfile 必须独立保管(KMS、HashiCorp Vault),泄露 = 加密失效。
列级加密
INSERT INTO users (email, ssn_enc) VALUES (?, AES_ENCRYPT(?, @key));
SELECT AES_DECRYPT(ssn_enc, @key) FROM users;应用层做加密更安全(钥匙不入库)。
KMS 集成
云上有 KMS plugin:
- AWS RDS:内置 KMS 集成
- 自建:HashiCorp Vault 提供 keyfile
动态数据脱敏
MariaDB Enterprise 有 data masking 插件。社区版可用 view 模拟:
CREATE SQL SECURITY DEFINER VIEW users_masked AS
SELECT
id,
CONCAT(LEFT(name, 1), '***') AS name,
CONCAT(LEFT(email, 3), '***@', SUBSTRING_INDEX(email, '@', -1)) AS email,
'***' AS phone
FROM users;
GRANT SELECT ON app.users_masked TO 'support'@'%';网络隔离
[mariadb]
bind-address = 127.0.0.1 # 只本机访问
# 或
bind-address = 10.0.0.10 # 只内网某 IP跨 VPC / 跨云:用 PrivateLink / 跨 region peering。
防火墙规则
# iptables
iptables -A INPUT -p tcp --dport 3306 -s 10.0.0.0/8 -j ACCEPT
iptables -A INPUT -p tcp --dport 3306 -j DROP
# ufw
ufw allow from 10.0.0.0/8 to any port 3306SQL 注入防御
永远用 prepared statements:
// ❌
db.query(`SELECT * FROM users WHERE email = '${email}'`);
// ✅
db.query('SELECT * FROM users WHERE email = ?', [email]);详见 ORM 最佳实践。
密码策略
INSTALL SONAME 'simple_password_check';
SET GLOBAL simple_password_check_minimal_length = 12;
SET GLOBAL simple_password_check_digits = 1;
SET GLOBAL simple_password_check_letters_same_case = 1;
SET GLOBAL simple_password_check_other_characters = 1;
-- 用户密码定期过期
ALTER USER 'app'@'%' PASSWORD EXPIRE INTERVAL 90 DAY;防爆破
-- 限连接尝试
INSTALL PLUGIN MAX_FAILED_LOGIN_ATTEMPTS SONAME 'auth_plugin_user_lock.so';
ALTER USER 'app'@'%' FAILED_LOGIN_ATTEMPTS 5 PASSWORD_LOCK_TIME 1;或在前置防火墙 / WAF 层做。
文件系统权限
chmod 700 /var/lib/mysql
chown -R mysql:mysql /var/lib/mysql错误日志、keyfile、配置文件:
chmod 600 /etc/mysql/keyfile /etc/mysql/my.cnf备份加密
mariabackup --backup --target-dir=/backup -uroot | \
openssl enc -aes-256-cbc -salt -k "$BACKUP_PASS" -out /backup/encrypted.bin或用 GPG。
漏洞响应
订阅:
- MariaDB Security Advisories
- CVE 数据库
升级永远跟 patch 版:11.4.4 → 11.4.5 这种 patch 升级通常无破坏性。
合规清单(GDPR / SOC2 / 等保)
- 全部 TLS
- 加密表空间
- 审计日志开启 + 长期保留
- 最小权限账号
- 密码策略
- 备份加密 + 异地
- 数据保留期限自动清理(
DELETE WHERE created_at < ...) - 用户数据导出 / 删除流程
- 访问日志可审计
- 应用层用 prepared statements
- 数据库不直接对公网暴露