首页/安全/漏洞与攻击面速查/SQL 注入原理与防护
Web 漏洞原理与防护55 条

SQL 注入原理与防护

SQL 注入源于把用户输入直接拼接进 SQL 语句,使输入被当作代码执行;防护核心是参数化查询(预编译)与最小权限账号,输入过滤与 WAF 只能作为兜底。

漏洞与攻击面速查安全更新于 2026-10-13

SQL 注入是什么

SQL 注入的根源是「数据被当成了代码」:把用户输入拼进 SQL 语句后,输入中的引号、注释符或 UNION 等结构会改变原语句的语义,让数据库执行攻击者构造的逻辑。它的危害随数据库账号权限放大,从越权读取数据,到批量篡改、删除,再到通过数据库的文件读写能力进一步触达主机。防护的正确顺序是先做参数化让输入永远只是数据,再用最小权限、统一错误处理和 WAF 收敛剩余风险。

基本信息

风险类别OWASP Top 10 2021 A03 注入类;CWE-89
成因字符串拼接 SQL,输入与语句结构未分离
直接危害数据越权读取、篡改、删除,认证绕过
扩大危害数据库具备文件读写或命令扩展能力时可威胁主机
根治手段参数化查询 / 预编译语句
兜底措施最小权限账号、统一错误页、输入白名单、WAF

常见出问题的地方

  • 登录与检索接口:name、keyword 等参数直接拼接进 WHERE 条件
  • 排序与分页:ORDER BY、LIMIT 后接字段名无法用占位符,被当成可拼接位置
  • ORM 的原生查询口子:框架里用原生命令拼 SQL,绕过了自动参数化
  • 报表与数据导出:动态筛选条件多,拼接逻辑复杂且少有安全评审
  • 存储过程与动态 SQL:过程内部再拼语句执行,权限往往偏高
  • 二次注入:写入时做了转义,读取后再拼进新语句时转义失效

拼接与参数化对比

拼接与参数化对比
危险:"SELECT * FROM users WHERE name = '" + name + "'"
安全(Python/DB-API):cursor.execute("SELECT * FROM users WHERE name = %s", (name,))
安全(Java):PreparedStatement ps = conn.prepareStatement("SELECT * FROM users WHERE name = ?"); ps.setString(1, name);
安全(PHP PDO):$st = $pdo->prepare('SELECT * FROM users WHERE name = ?'); $st->execute([$name]);
# 关键点:占位符只绑定值,不参与语句结构解析
# 表名、排序字段等无法参数化的位置,用白名单映射到固定字符串

数据库最小权限示例

数据库最小权限示例
CREATE USER 'app'@'10.%' IDENTIFIED BY '<强随机口令>';
GRANT SELECT, INSERT, UPDATE, DELETE ON appdb.* TO 'app'@'10.%';
-- 业务账号不给 FILE、DROP、GRANT 等能力,避免注入被放大为主机控制
-- 只允许应用网段访问,数据库实例不监听公网地址
FLUSH PRIVILEGES;

注入类型与观测特征

类型触发条件常见观测特征
联合查询注入页面回显查询结果响应中出现额外数据行或列错位
报错注入错误信息回显到页面URL 参数含函数调用,页面返回数据库报错
布尔盲注仅能区分真伪两种响应同参数多次请求返回长短或内容差异
时间盲注真假无差异请求耗时规律性增加,且与参数相关
堆叠查询驱动允许多语句执行单次请求触发意料外的写操作
判断是否真正修复,看的是代码里的拼接点是否消灭,而不是页面是否报错消失——把报错藏起来只是减少线索,不改变可利用性。
WAF 规则能挡住大量自动化扫描,但对编码变形与人工构造的语句经常失效,定位只能是缓冲时间,不是整改手段。

验证与回归要点

  • 用与发现时相同的参数路径复测,确认该参数已不改变语句结构
  • 检查同类接口是否一起修复:同一模板生成的接口往往成批存在同一问题
  • 回归正常业务路径:参数化改造后要确认原有查询、排序、模糊匹配结果不变
  • 看日志与监控:修复后异常 SQL 报错与大量相似请求应同步下降
  • 留存证据:请求与响应摘要、代码提交记录一并归档,便于后续审计
参数化之后还有一处细节:LIKE 查询里的百分号与下划线属于通配符,需要在应用层转义,否则用户输入仍然能改变匹配范围,这是逻辑差异而非注入,但同样影响结果正确性。

易错点

  • 分页参数做了参数化但 ORDER BY 字段仍是拼接:拼接点不止 WHERE,排序、表名、LIKE 通配符都是入口
  • 用转义函数替代参数化不可靠:字符集、数据库类型与转义函数覆盖范围差异会造成绕过
  • 给业务账号开 DBA 或 FILE 权限:一旦注入成功,数据泄露立刻升级为主机文件读写
  • 把数据库错误信息直接回显到生产页面:为报错注入提供便利,也暴露表结构与版本
  • 只在网关层做过滤而应用层继续拼接:更换入口、内部调用或直连数据库的通道都会绕过
  • 修复后只验证页面不再报错:应使用与原发现问题相同的参数路径复测,确认语句结构与原判定一致

数据来源与参考

  • OWASP SQL Injection Prevention Cheat Sheet
  • MySQL 8.0 Reference Manual(Prepared Statements)
​‌‌​​‌​​​‌‌​‌‌‌‌​‌‌​​​‌‌​‌‌‌​​‌‌​​‌​‌‌‌​​‌‌‌​​​‌​‌‌​‌​​‌​‌‌‌​​​‌​‌‌​‌​​‌​‌‌​​​‌‌​‌‌‌​‌​​​‌‌​‌‌‌‌​​‌​‌‌‌​​‌‌​​​‌‌​‌‌​‌‌‌‌​‌‌​‌‌​‌