MariaDB 中文社区

安全加固

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',0

general_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 = 4

keyfile 格式:

1;DEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEF
2;BEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEAD

keyfile 必须独立保管(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 3306

SQL 注入防御

永远用 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。

漏洞响应

订阅:

升级永远跟 patch 版:11.4.4 → 11.4.5 这种 patch 升级通常无破坏性。

合规清单(GDPR / SOC2 / 等保)

  • 全部 TLS
  • 加密表空间
  • 审计日志开启 + 长期保留
  • 最小权限账号
  • 密码策略
  • 备份加密 + 异地
  • 数据保留期限自动清理(DELETE WHERE created_at < ...
  • 用户数据导出 / 删除流程
  • 访问日志可审计
  • 应用层用 prepared statements
  • 数据库不直接对公网暴露

延伸

本页目录