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,误操作或注入后的破坏面极大。数据库迁移应使用单独账号和受控发布流程。
