Skip to content

MySQL 安全与权限

数据库安全的核心不是“设置复杂 root 密码”,而是让身份、网络、权限、传输、审计和密钥形成闭环。

账号模型

MySQL 账号由 user@host 共同标识:

sql
create user 'app_rw'@'10.%'
identified by '由密钥系统生成的高强度密码';

grant select, insert, update, delete
on app_db.*
to 'app_rw'@'10.%';

show grants for 'app_rw'@'10.%';

生产实践:

  • 应用不使用 root,读写、只读、迁移和运维账号分离。
  • 来源主机范围尽量收窄,避免无必要的 '%'
  • 不授予应用 SUPER、全局权限或任意 DDL 权限。
  • 人员账号与应用账号分开,离职和角色变更及时回收。
  • 密码、证书和 Token 放在密钥系统,不写入仓库、镜像和日志。

Role

MySQL 8 支持角色,适合把权限集合与人员账号分离:

sql
create role 'report_reader';
grant select on app_db.* to 'report_reader';
grant 'report_reader' to 'analyst'@'10.%';
set default role 'report_reader' to 'analyst'@'10.%';

定期审计实际授权,避免权限只增不减。

SQL 注入

错误示意:

java
String sql = "select * from users where username = '" + username + "'";

正确方向是参数化查询或 ORM 绑定参数。参数化保护的是“值”,动态表名、列名和排序方向不能当普通参数绑定,应使用白名单映射。

同时注意:

  • 不用转义函数替代参数化。
  • 数据库最小权限可以降低注入后的破坏半径,但不能替代修复。
  • 错误响应不要暴露 SQL、表结构和堆栈。
  • 慢日志、审计日志和 APM 参数需脱敏。

网络与 TLS

  • 数据库放在私网,不直接暴露公网。
  • 防火墙和安全组只允许应用网段或代理访问。
  • 跨主机和跨网络传输启用并验证 TLS,不只写 ssl=true 就假定生效。
  • 证书要验证 CA 和主机身份,并建立轮换与到期告警。
  • 管理端口通过堡垒机、VPN 或受控运维通道访问。

查看连接加密状态:

sql
show session status like 'Ssl_cipher';

静态数据、备份和日志

数据库文件、binlog、备份和导出文件都可能包含完整敏感数据:

  • 使用磁盘或云存储加密,并控制 KMS 权限。
  • 备份单独授权,限制下载,设置生命周期和不可变保护。
  • 非生产环境使用脱敏数据,不直接复制生产库。
  • 日志避免输出密码、身份证、手机号、Token、密钥和完整支付信息。
  • 加密列要考虑查询、索引、密钥轮换和历史数据迁移,不能只在 SQL 中硬编码密钥。

删除与审计

业务软删除不等于物理删除,也不等于满足隐私合规。数据还可能存在于:

  • 主库旧版本和 undo。
  • 副本。
  • binlog。
  • 备份和快照。
  • 搜索、缓存、数仓和日志。

合规删除要设计跨系统传播、备份到期策略、审计证据和恢复后的再次删除流程。

安全基线检查

sql
select user, host, account_locked, password_expired
from mysql.user;

select grantee, privilege_type, table_schema
from information_schema.schema_privileges
order by grantee, table_schema;

还要检查:匿名账号、测试库、空密码风险、远程 root、陈旧账号、过度授权、TLS、审计覆盖、备份访问和补丁版本。

高频面试题

防 SQL 注入只用 PreparedStatement 就够吗

它能解决大部分值参数注入,但动态标识符、排序字段、拼接片段仍需白名单;同时还要最小权限、错误隐藏、依赖升级、审计与异常检测。安全应是多层防御。

为什么应用账号不能有 DDL 权限

应用运行时通常只需 DML。DDL 可以删表、改结构并获取强 MDL,误操作或注入后的破坏面极大。数据库迁移应使用单独账号和受控发布流程。