仅靠参数化查询不足以防止横向越权,因高权限账号可绕过 SQL 拼接路径执行敏感操作;必须遵循最小权限原则,按模块、表、操作粒度显式授权,并严控连接池配置中的权限陷阱。

为什么只靠参数化查询还不够
参数化查询能拦住大部分拼接 SQL 的漏洞,但挡不住权限过大带来的横向越权。比如应用用 root 账号连数据库,即使所有查询都用了 PreparedStatement,攻击者一旦通过其他漏洞(如反序列化、XXE)拿到应用执行上下文,就能直接调用 SELECT * FROM mysql.user 或写入 INTO OUTFILE —— 这些不走业务 SQL 拼接路径。
连接池账号必须遵循最小权限原则
应用连接池配置的数据库账号,只应拥有当前模块必需的表级读写权限,且禁止授予 GRANT OPTION、FILE、PROCESS、SUPER 等高危权限。
- Web 前端服务账号:仅允许对
users、orders表执行SELECT、INSERT、UPDATE(不含DELETE) - 后台任务账号:若只需清理过期日志,只授
DELETE ON logs.* WHERE created_at < DATE_SUB(NOW(), INTERVAL 7 DAY)类似能力(通过存储过程封装,而非开放 DELETE 权限) - 绝对禁止在生产环境使用
CREATE USER、DROP TABLE、SHOW DATABASES权限
MySQL 中如何安全创建连接池账号
别用 GRANT ALL PRIVILEGES ON *.* TO 'app' —— 这等于把锁孔交出去还附送万能钥匙。应该按库、按表、按操作粒度显式授权。
CREATE USER 'app_rw'@'10.20.%.%' IDENTIFIED BY 'strong-pass-2024'; GRANT SELECT, INSERT, UPDATE ON myapp.users TO 'app_rw'@'10.20.%.%'; GRANT SELECT, INSERT ON myapp.orders TO 'app_rw'@'10.20.%.%'; FLUSH PRIVILEGES;
注意:IP 段限制(如 '10.20.%.%')比 '%' 更安全;密码必须启用强策略;账号名避免含 admin、root 等暗示高权的词。
连接池配置里容易被忽略的权限陷阱
很多团队改了数据库账号权限,却忘了连接池本身可能开启危险特性。比如 HikariCP 的 connection-init-sql、Druid 的 initConnectionSqls,如果配了 SET sql_mode='' 或 SET autocommit=1 之外的语句,可能绕过权限限制触发执行。
- 禁用任何初始化 SQL,除非明确需要且已审计其权限影响
- 确认连接池未启用
allowMultiQueries=true(MySQL JDBC)—— 它会让;分隔的多语句逃逸参数化保护 - 检查是否启用了
autoReconnect=true,它在重连时可能用原始凭证重新认证,若凭证泄露则扩大影响面
权限不是设一次就完事的事。连接池账号的权限边界,得和代码调用链、部署拓扑、运维流程一起看——漏掉任意一环,防御就只剩纸糊的墙。