创建用户时就限定来源和密码强度
普通用户只读权限不是“先建再锁”,而是从第一步就卡住风险面。比如允许任意IP连接的
'user'@'%',哪怕只给
SELECT,也可能被爆破或撞库——生产环境必须用内网段限制,例如
'reporter'@'192.168.20.%'。密码也不能是弱口令,MySQL 8.0+ 默认启用
validate_password插件,建议至少含大小写字母、数字、特殊字符,长度 ≥12。
只授权具体库表,禁用 GRANT SELECT ON *.*
全局只读看似省事,实则会暴露
mysql、
information_schema、
performance_schema等系统库,攻击者能查账号哈希、权限列表、慢查询日志等敏感信息。正确做法是逐库授权:
GRANT SELECT ON sales_db.* TO 'reporter'@'192.168.20.%'; GRANT SELECT ON analytics_db.fact_orders TO 'reporter'@'192.168.20.%';
如果后续新增库,必须手动补授权,不能图省事开全局。
显式回收高危权限,别信“没授就不带”
MySQL 权限继承机制复杂:旧版本用户可能隐含
USAGE以外的默认权限;复制环境中
REPLICATION SLAVE权限可能被误授;甚至某些运维脚本会悄悄加
SUPER。所以必须主动清理:
REVOKE INSERT, UPDATE, DELETE, DROP, CREATE, ALTER, INDEX, LOCK TABLES, EXECUTE ON *.* FROM 'reporter'@'192.168.20.%';
REVOKE SUPER, REPLICATION CLIENT, REPLICATION SLAVE, FILE, PROCESS ON *.* FROM 'reporter'@'192.168.20.%';
执行后务必用
SHOW GRANTS FOR 'reporter'@'192.168.20.%';确认输出里只有
SELECT相关行。
验证要覆盖边界场景,不止 INSERT
报错
只测
INSERT成功与否太表面。真实绕过只读的方式更多: 尝试
CREATE TEMPORARY TABLE—— 这不走
read_only检查,但若用户有
CREATE TEMPORARY TABLES权限,就能构造中间数据 执行
SELECT ... INTO OUTFILE—— 若用户有
FILE权限,可导出任意可查数据到服务器磁盘 连上后跑
SHOW PROCESSLIST;—— 如果没 revoke
PROCESS,能看到其他用户正在执行的 SQL,包括带密码的连接串
最小权限不是“够用就行”,而是“多一个字节都不给”。只要没明确业务需求,
FILE、
PROCESS、
SHOW VIEW、
TRIGGER全部默认 revoke。
