最小权限能拦住大部分SQL注入,是因为注入只能以应用账号身份执行SQL;若该账号仅被授予特定表、字段的有限权限(如SELECT),攻击者便无法跨表查询、读取系统视图或执行高危操作,实际危害大幅受限。

只要数据库账号不配成 root 或 sa,绝大多数 SQL 注入攻击连表名都查不到,更别说拖库。
为什么最小权限能拦住大部分注入?
SQL 注入本身不等于“拿到数据库所有权限”。它只是让攻击者借你的应用账号执行任意 SQL。如果这个账号只能查 users 表的 name 和 email 字段,那即使用 UNION SELECT 也只能源源不断吐出这两列——其他表、字段、系统视图、存储过程统统不可见。
真实案例中,90% 的 Web 应用被注入后只泄露了部分用户信息,根本原因就是数据库账号早被限制在 SELECT 权限 + 单个业务库 + 少数几张表。
具体该给什么权限?看场景定
别直接 GRANT ALL ON *.* TO 'app',按实际调用行为收紧:
- 纯读接口(如商品列表、用户资料页)→ 只授
SELECT,且限定到具体库和表,例如:GRANT SELECT ON myapp.products TO 'web_app'@'%'; - 登录验证逻辑 → 如果只查
users表的username和password_hash,就别给整张表权限,用视图封装:CREATE VIEW login_view AS SELECT username, password_hash FROM users;,再授SELECT给这个视图 - 后台导出功能 → 需要
SELECT多张表?用角色管理,建export_role,加权限,再把账号GRANT export_role TO 'report_user'@'%'; - 绝对禁止
FILE、EXECUTE、PROCESS、SUPER这类高危权限,哪怕只给测试环境也不行
容易被忽略的三个坑
权限配得再细,踩错这三点照样白搭:
- MySQL 5.7+ 默认启用
sql_mode = ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,但很多旧项目手动关了。一旦关闭,攻击者可用SELECT 1,2,3 FROM dual绕过字段数校验,强行UNION出敏感系统表 —— 检查SELECT @@sql_mode;,确保没关严格模式 - PostgreSQL 中,
publicschema 默认可读。即使账号没显式授权,只要没REVOKE USAGE ON SCHEMA public FROM PUBLIC;,攻击者就能SELECT table_name FROM information_schema.tables扫库 —— 必须显式回收默认权限 - 账号密码硬编码在配置文件里?哪怕权限再小,一旦服务器被拿 shell,攻击者直接读配置连库。必须用密钥管理服务(如 HashiCorp Vault)或运行时注入凭证,禁止明文存盘
最小权限不是一劳永逸的配置项,而是每次上线新功能前都要重审的 checklist:这个接口到底需要哪几个字段?能不能用视图/角色进一步隔离?有没有残留的 GRANT ALL 历史账号?

















