# SQL注入入门与防御(软件设计师/安全审计通用笔记) > SQL注入(SQLi)CWE-89:**攻击者将SQL代码插入应用输入参数,后端未做安全处理,直接拼接到SQL语句,被数据库执行**。 > 核心本质:**把用户可控输入,当成SQL代码执行;业务混淆了「数据」和「代码」边界** ## 一、简单原理示例 原始业务逻辑:根据id查询用户 ```java // 危险写法:字符串拼接 String sql = "select * from user where id = " + userInput; ``` 攻击者传入:`1 or 1=1` 拼接后SQL变成: ```sql select * from user where id = 1 or 1=1 ``` 条件永远成立,查出全部用户数据。 字符型注入示例(带单引号闭合) ```java String sql = "select * from user where name = '" + userInput + "'"; ``` 输入payload:`' or 1=1 -- ` 拼接结果: ```sql select * from user where name = '' or 1=1 -- ' ``` `--` 后面内容作为注释,闭合原有单引号,实现脱库。 ## 二、SQL注入常见分类 1. **联合查询注入 Union Select** `union select 1,version(),database()`,把查询结果和原查询合并,读取库名、版本、表、字段。 > 前提:前后查询列数一致,页面会回显查询结果(回显型注入) 2. **布尔盲注** 页面**不直接返回数据**,但页面内容根据SQL真假变化。 payload:`' and length(database())>5 -- `,通过页面正常/异常判断条件真假,逐字符猜内容。 3. **时间盲注** 页面无回显、无布尔差异;使用`sleep(5)`,通过响应延迟判断语句是否执行。 payload:`' and sleep(5) -- ` 4. **报错注入** 利用数据库报错函数(updatexml、extractvalue),报错信息带出查询数据。 适用于页面输出数据库错误信息场景。 5. **二次注入**(进阶,前面笔记讲过) payload第一次入库被转义,后续读取库中数据直接拼接SQL触发注入。 > 补充:堆叠注入 `;` 分号,执行多条SQL;部分数据库支持。 ## 三、注入产生必备2个条件 1. 用户可控参数拼入SQL语句 2. 没有使用**预编译参数化查询** ## 四、识别测试(授权测试场景) ### 基础测试Payload 1. 单引号测试:`'` 页面出现数据库报错、语法错误 → 大概率存在注入 2. 逻辑判断:`' and 1=1--`、`' and 1=2--` 对比两个请求页面返回差异(布尔盲注) 3. 延时测试:`' and sleep(3)--`,观察响应时间(时间盲注) ### 注入点常见位置 GET参数、POST表单、JSON参数、Cookie、HTTP请求头(User-Agent/Referer) ## 五、防御方案(优先级从高到低) ### ✅ 1. 参数化预编译查询(治本,首选) 原理:SQL语句结构预先发送给数据库,参数单独传递;**参数永远被当做纯数据,不会解析为SQL代码**。 MyBatis示例: ```xml select * from user where id = #{userId} ``` ```xml select * from user where id = ${userId} ``` Java JDBC原生预编译示例: ```java String sql = "select * from user where name = ?"; PreparedStatement pstmt = conn.prepareStatement(sql); pstmt.setString(1, userInput); // 参数单独传入,不会执行SQL ``` > 注意:表名、排序字段无法用占位符绑定,这类场景**必须使用白名单**,不能直接拼接用户输入。 ### ✅ 2. 输入校验(辅助防护,不能单独依靠) - 数值类参数:正则仅允许数字 - 字符串业务:白名单,只允许业务规定字符;**黑名单(过滤or/union/select)极易被绕过** ### ✅ 3. 最小权限原则(缩小危害) 数据库账号权限收紧: - Web业务账号,**禁止drop、alter、create**等高权限 - 只授予业务必需表select/insert/update,禁止访问系统库information_schema ### ✅ 4. 关闭详细数据库报错 不要把原生SQL语法错误、表名、字段信息返回前端,防止攻击者利用报错注入。统一返回自定义错误页。 ### ✅ 5. WAF Web应用防火墙(兜底辅助) 拦截union、sleep、单引号等注入特征。 > WAF仅辅助,变形注入容易绕过,**不能替代代码层预编译** ## 六、常见误区 1. ❌ 前端过滤特殊字符就能防注入:前端校验客户端可控,可以抓包修改绕过 2. ❌ 使用ORM就不会注入:MyBatis `${}`、原生raw sql拼接输入,依然会注入 3. ❌ 转义单引号就安全:存在二次注入、编码绕过等场景,转义不是根治方案 4. ❌ 不回显页面就不存在注入:布尔盲注、时间盲注无直接数据回显,依然可脱库 ## 七、漏洞笔记模板(和前面漏洞格式统一) 漏洞名称:结构化查询语言注入(SQL Injection CWE-89) 漏洞类型:注入漏洞 风险等级:高危 前置权限:可提交可控请求参数 原理:应用将用户可控输入直接拼接进SQL语句,未使用预编译,攻击者可构造恶意SQL片段,被数据库执行,读取/修改数据库数据。 复现步骤: 1. 在参数位置提交单引号`'`,触发数据库语法报错 2. 构造and 1=1 / and 1=2 payload,观察页面差异 3. 使用union/时间盲注读取数据库信息 缓解方案:临时部署WAF拦截注入特征;关闭详细数据库报错 永久修复:全部SQL使用预编译参数化查询;数据库账号最小权限;输入白名单校验 ## 八、蓝队日志/审计要点 - 监控请求参数包含 union, select, sleep, extractvalue, updatexml - 监控数据库大量异常查询、批量查询information_schema - 审计代码:搜索代码中字符串拼接SQL、Mybatis `${`