网安入门之MySQL后端基础

数据库 (Database)

数据库是指长期存储在计算机中的,有组织、可共享的数据集合。它通过表、列、行等结构来组织数据,目的是使数据可以高效存储、检索和管理。数据库通常包括多个表,每个表存储与特定主题或对象相关的数据

数据库管理系统 (DBMS)

数据库管理系统(DBMS)是用于创建、管理、操作、维护数据库的软件。它提供了用户与数据库交互的接口,支持数据的增、删、改、查等操作,并确保数据的完整性、安全性和一致性。常见的DBMS有:

  1. MySQL:开源的关系型数据库管理系统,广泛用于Web开发中
  2. MSSQL:微软推出的关系型数据库管理系统,通常用于企业级应用
  3. ORACLE:强大的关系型数据库系统,广泛应用于大型企业
  4. Redis:一个高性能的键值数据库,通常用于缓存和实时数据处理
  5. Access:微软推出的小型数据库管理系统,适合小型应用

Excel 与 DBMS

虽然Excel本身不是一个数据库管理系统,但它可以用作简易数据库来存储和组织数据。Excel通过表格的形式组织数据,可以进行基本的增、删、改、查操作,适合小规模数据管理。不过,Excel的功能有限,不具备DBMS的高效性、并发控制、事务处理等特性。因此,Excel不适合处理大量数据或复杂的数据库操作

数据库的操作

数据库通常支持以下基本操作:

  1. 增(INSERT) :向数据库表中插入新数据
    • 通过 INSERT 语句可以添加新记录到表中
  2. 删(DELETE) :从数据库表中删除数据
    • 使用 DELETE 语句来删除一行或多行数据
  3. 改(UPDATE) :更新数据库表中的已有数据
    • 使用 UPDATE 语句来修改表中的记录
  4. 查(SELECT) :查询数据库中的数据
    • 使用 SELECT 语句来检索数据,可以进行复杂的过滤、排序、连接等操作
  5. 新建数据库(CREATE DATABASE) :创建一个新的数据库
    • 使用 CREATE DATABASE 语句可以新建一个数据库
  6. 新建数据表(CREATE TABLE) :在数据库中创建一个新的表
    • CREATE TABLE 语句定义表的结构,包括列名、数据类型、主键等
  7. 新建数据列(ALTER TABLE) :向已有的数据表中添加、删除或修改列
    • 使用 ALTER TABLE 可以添加、删除或修改表的字段,允许对表进行扩展或调整

数据库表的组成

数据库表是由行(记录)和列(字段)组成的二维结构。每个表有:

  1. (Field/Column):每列存储一种类型的数据,如 IDNameAge
  2. (Record/Row):每行表示一条具体的数据记录,每行数据包含所有列的值

数据库操作示例

  1. 插入数据(INSERT):
plain 复制代码
//创建数据表
CREATE TABLE users (
    id INT AUTO_INCREMENT PRIMARY KEY,
    name VARCHAR(100),
    age INT
);
INSERT INTO users (name, age) VALUES ('Alice', 30);

可见已经插入:

  1. 删除数据(DELETE):
plain 复制代码
DELETE FROM users WHERE name = 'Alice'

因为已经删除了,再次查询就没有了

  1. 更新数据(UPDATE):
plain 复制代码
UPDATE users SET age = 31 WHERE name = 'Alice'
  1. 查询数据(SELECT):
plain 复制代码
SELECT * FROM users WHERE age > 25

数据库事务

DBMS通常支持事务的管理。一个事务是一组操作的集合,它要么完全执行,要么完全不执行。事务保证了数据库的ACID特性(原子性、一致性、隔离性、持久性)

  1. 原子性(Atomicity):事务中的所有操作要么全部执行,要么全部不执行
  2. 一致性(Consistency):事务的执行使得数据库从一个一致性状态转变为另一个一致性状态
  3. 隔离性(Isolation):事务的执行不受其他事务的干扰
  4. 持久性(Durability):事务一旦提交,它的结果就永久保存在数据库中

总结

plain 复制代码
SELECT * FROM `userinfo` WHERE 1
查询 想要查询到的结果(数据列的名称) 从哪儿来(从哪个数据表操作) 资源归属(数据表的名称) where 限制条件(key=value)
INSERT INTO 表名(字段名称1, 字段名称2) VALUES (字段值1,字段值2)
#可以不用对记录中每一个字段都赋值,但是字段名称和字段值数量要一致
UPDATE 表名 SET 字段 = '值' WHERE 条件
DELETE FROM 表名 WHERE 条件 
#delete没有输入字段,是因为我们是将整条记录一起删除的

1. AND

AND 是 SQL 中的逻辑运算符,用于在 WHERE 子句中组合多个条件。只有当所有条件都为 TRUE 时,整个表达式才返回 TRUE

用法

当多个条件必须同时满足时,可以使用 AND 连接。例如,查询年龄大于 20 且性别为男性的所有用户:

plain 复制代码
SELECT * FROM users WHERE age > 20 AND gender = 'Male';

2. OR

OR 也是 SQL 中的逻辑运算符,用于在 WHERE 子句中组合多个条件。只要有一个条件为 TRUE,整个表达式就返回 TRUE

用法

当多个条件中至少有一个条件满足时,可以使用 OR 连接。例如,查询年龄大于 20 或性别为男性的所有用户:

plain 复制代码
SELECT * FROM users WHERE age > 20 OR gender = 'Male';

3. ORDER BY(后期用来SQL注入攻击探测列数)

ORDER BY 用于对查询结果进行排序。你可以指定按一个或多个列进行排序,并选择升序(ASC)或降序(DESC)排列。

用法 :默认是升序排列(ASC),如果需要降序排列,可以明确指定 DESC。例如,按 age 升序排列用户:

plain 复制代码
SELECT * FROM users ORDER BY age ASC;

如果要按多个字段排序,可以在 ORDER BY 后列出多个字段,按顺序排列。例如,先按 age 升序排列,再按 name 字母顺序排列:

plain 复制代码
SELECT * FROM users ORDER BY age ASC, name ASC;

4. UNION(后期用来联合查询攻击)

UNION 用于将两个或多个 SELECT 查询的结果合并成一个结果集。注意,UNION 会去除重复的记录。如果需要包含所有记录(包括重复记录),可以使用 UNION ALL

用法UNION:将两个查询的结果合并,并去掉重复的行。UNION ALL:将两个查询的结果合并,包括重复的行。例如,查询 users 表和 employees 表的所有 name 字段,合并结果:

plain 复制代码
SELECT name FROM users UNION SELECT name FROM employees;

如果不去掉重复记录,可以使用 UNION ALL

plain 复制代码
SELECT name FROM users UNION ALL SELECT name FROM employees;

总结

  1. **AND**:用来连接多个条件,所有条件都满足时,返回 TRUE
  2. **OR**:用来连接多个条件,只要有一个条件满足时,返回 TRUE
  3. **ORDER BY**:用来排序查询结果,可以指定排序的列及排序顺序。
  4. **UNION**:用来合并多个 SELECT 查询的结果,默认去掉重复行,可以使用 UNION ALL 保留重复行

1. LIKE

LIKE 是 SQL 中用于模式匹配的运算符,常用于 WHERE 子句中,用来匹配列中的某些字符模式。通常与通配符(如 %_)一起使用。

用法

%:表示零个或多个字符。

_:表示一个字符。

示例:匹配以特定字符开头的值,查询名字以 "A" 开头的所有用户:
plain 复制代码
SELECT * FROM users WHERE name LIKE 'A%';

这条查询会返回所有名字以 "A" 开头的用户,例如 "Alice"、"Alex"。

  1. 匹配包含特定字符的值
    查询名字中包含 "li" 的所有用户:
plain 复制代码
SELECT * FROM users WHERE name LIKE '%li%';

这条查询会返回名字中包含 "li" 的所有用户,例如 "Alice"、"Bill"。

  1. 匹配特定字符数的值
    查询名字的第二个字符是 "l" 的用户:
plain 复制代码
SELECT * FROM users WHERE name LIKE '_l%';

这条查询会返回名字第二个字符是 "l" 的用户,例如 "Alice"。

2. GROUP BY

GROUP BY 用于将查询结果按某些列进行分组。它通常与聚合函数(如 COUNTSUMAVGMAXMIN 等)一起使用,用来对每个分组执行聚合操作。

用法GROUP BY 将结果集按指定的列进行分组,然后可以对每个分组执行聚合操作。

示例:按年龄分组并统计每个年龄段的用户数

查询每个年龄段的用户数量:

plain 复制代码
SELECT age, COUNT(*) AS num_users FROM users GROUP BY age;

这条查询会按 age 列对用户进行分组,并返回每个年龄的用户数量。

  1. 按部门分组并求每个部门的最大工资
    查询每个部门的最高工资:
plain 复制代码
SELECT department, MAX(salary) AS max_salary FROM employees GROUP BY department;

这条查询会返回每个部门中薪资最高的员工工资。

  1. 按多个列分组
    按年龄和性别分组,并计算每个分组的用户数量:
plain 复制代码
SELECT age, gender, COUNT(*) AS num_users FROM users GROUP BY age, gender;

这条查询会返回每个年龄和性别组合下的用户数量。

3. IN

IN 是 SQL 中的一种运算符,用于检查某个值是否在指定的一组值中。通常用于 WHERE 子句中,可以简化多个 OR 条件的表达式。

用法IN 用于匹配指定列的值是否在给定的集合中。

示例:查询年龄为 20、25 或 30 的用户

使用 IN 来匹配年龄为 20、25 或 30 的用户:

plain 复制代码
SELECT * FROM users WHERE age IN (20, 25, 30);

这条查询会返回年龄是 20、25 或 30 的用户。

  1. 查询名字为 "Alice"、"Bob" 或 "Charlie" 的用户
    使用 IN 来匹配名字为 "Alice"、"Bob" 或 "Charlie" 的用户:
plain 复制代码
SELECT * FROM users WHERE name IN ('Alice', 'Bob', 'Charlie');

这条查询会返回名字为 "Alice"、"Bob" 或 "Charlie" 的用户。

  1. 与子查询一起使用
    使用子查询返回的结果作为 IN 的参数。例如,查询所有在部门 A 或部门 B 的员工:
plain 复制代码
SELECT * FROM employees WHERE department IN (SELECT department FROM departments WHERE name IN ('A', 'B'));

这条查询会返回所有在部门 A 或部门 B 的员工。

利用 LIKE 进行 SQL 注入:

LIKE 通常在数据库查询中作为过滤条件使用。如果输入没有正确验证或过滤,攻击者可能会通过构造恶意输入,导致 SQL 注入。

例如,如果网站允许用户通过查询名字来查找用户,但没有正确处理输入,攻击者可能会尝试通过 LIKE 运算符注入 SQL 代码。

示例注入攻击: 假设查询语句为:

plain 复制代码
SELECT * FROM users WHERE name LIKE '%[用户输入]%';

攻击者可以输入如下内容:

plain 复制代码
' OR '1'='1

这会导致 SQL 查询变成:

plain 复制代码
SELECT * FROM users WHERE name LIKE '% OR '1'='1%';

这样,OR '1'='1' 总是为真,导致返回所有记录,从而绕过认证或过滤。

利用 GROUP BY 进行 SQL 注入:

攻击者可能利用 GROUP BY 子句注入恶意 SQL 代码。假设应用程序没有正确处理用户输入,攻击者可以插入恶意的 GROUP BY 子句,尝试影响查询结果或利用数据库的结构信息。

示例注入攻击: 假设查询语句是:

plain 复制代码
SELECT department, COUNT(*) FROM employees GROUP BY department;

攻击者输入恶意代码:

plain 复制代码
' GROUP BY CONCAT(username, password) --

这可能导致查询变成:

plain 复制代码
SELECT department, COUNT(*) FROM employees GROUP BY CONCAT(username, password) -- ;

CONCAT(username, password) 会拼接 usernamepassword 列的值,并可能返回这些敏感信息。

利用 IN 进行 SQL 注入:

攻击者可能在 IN 子句中注入恶意值,导致 SQL 查询失效或获取不必要的数据。注入攻击通常利用 IN 语句的数组特性来篡改查询。

示例注入攻击: 假设查询语句是:

plain 复制代码
SELECT * FROM users WHERE name IN ('[用户输入]');

攻击者输入恶意内容:

plain 复制代码
' OR '1'='1' --

这会导致查询变成:

plain 复制代码
SELECT * FROM users WHERE name IN ('', ' OR '1'='1' --');

由于 1 = 1 始终为真,查询可能返回所有记录,绕过身份验证或其他限制。

在 PHP 中,可以使用 mysqli 扩展来与 MySQL 数据库进行交互。mysqli(MySQL Improved)提供了一个更为现代化和灵活的方式来操作 MySQL 数据库,支持面向过程和面向对象的编程方式。

1. 连接 MySQL 数据库

在执行任何操作之前,首先需要建立与 MySQL 数据库的连接。使用 mysqli_connectnew mysqli 方法。

面向过程:
plain 复制代码
$conn = mysqli_connect("localhost", "username", "password", "database_name");
if (!$conn) {
    die("连接失败: " . mysqli_connect_error());
}
面向对象:
plain 复制代码
$conn = new mysqli("localhost", "username", "password", "database_name");
if ($conn->connect_error) {
    die("连接失败: " . $conn->connect_error);
}

2. 增、删、改(INSERT、UPDATE、DELETE)

在执行增、删、改操作时,使用 mysqli_query 函数。mysqli_query 返回一个布尔值(TRUEFALSE),表示查询是否成功执行。

插入数据(INSERT):
plain 复制代码
$sql = "INSERT INTO users (name, age) VALUES ('Alice', 30)";
if (mysqli_query($conn, $sql)) {
    echo "新记录插入成功";
} else {
    echo "错误: " . $sql . "<br>" . mysqli_error($conn);
}
更新数据(UPDATE):
plain 复制代码
$sql = "UPDATE users SET age = 31 WHERE name = 'Alice'";
if (mysqli_query($conn, $sql)) {
    echo "记录更新成功";
} else {
    echo "错误: " . $sql . "<br>" . mysqli_error($conn);
}
删除数据(DELETE):
plain 复制代码
$sql = "DELETE FROM users WHERE name = 'Alice'";
if (mysqli_query($conn, $sql)) {
    echo "记录删除成功";
} else {
    echo "错误: " . $sql . "<br>" . mysqli_error($conn);
}
面向对象的语法:
plain 复制代码
$sql = "INSERT INTO users (name, age) VALUES ('Bob', 25)";
if ($conn->query($sql) === TRUE) {
    echo "新记录插入成功";
} else {
    echo "错误: " . $sql . "<br>" . $conn->error;
}

3. 查询操作(SELECT)

当执行查询操作(SELECT)时,mysqli_query 返回一个结果集。如果查询成功且有结果,它返回一个 mysqli_result 对象。你需要使用 mysqli_fetch_assocmysqli_fetch_row 来解析查询结果。

查询数据(SELECT):
plain 复制代码
$sql = "SELECT id, name, age FROM users";
$result = mysqli_query($conn, $sql);

if (mysqli_num_rows($result) > 0) {
    // 输出每行数据
    while($row = mysqli_fetch_assoc($result)) {
        echo "id: " . $row["id"] . " - Name: " . $row["name"] . " - Age: " . $row["age"] . "<br>";
    }
} else {
    echo "没有结果";
}
面向对象的语法:
plain 复制代码
$sql = "SELECT id, name, age FROM users";
$result = $conn->query($sql);

if ($result->num_rows > 0) {
    while ($row = $result->fetch_assoc()) {
        echo "id: " . $row["id"] . " - Name: " . $row["name"] . " - Age: " . $row["age"] . "<br>";
    }
} else {
    echo "没有结果";
}

4. **mysqli_fetch_assoc**** 和 **mysqli_fetch_row** 解析查询结果**

在查询数据时,你可以使用两种常用的函数来解析结果集:

**mysqli_fetch_assoc**:返回一个关联数组,其中数组的键是列名(字段名)。这种方法通常用于需要字段名的情况。

**mysqli_fetch_row**:返回一个索引数组,其中数组的键是列的数字索引。适用于你只关心结果的顺序,而不关心字段名称的情况。

使用 mysqli_fetch_assoc
plain 复制代码
$row = mysqli_fetch_assoc($result);
echo "id: " . $row["id"] . " - Name: " . $row["name"] . " - Age: " . $row["age"] . "<br>";
使用 mysqli_fetch_row
plain 复制代码
$row = mysqli_fetch_row($result);
echo "id: " . $row[0] . " - Name: " . $row[1] . " - Age: " . $row[2] . "<br>";

mysqli_fetch_assoc 返回的结果是一个关联数组,可以通过字段名直接访问数据。而 mysqli_fetch_row 返回的是一个索引数组,字段值是通过列索引来访问的(从 0 开始)。

5. 关闭连接

操作完成后,别忘了关闭数据库连接。

面向过程:
plain 复制代码
mysqli_close($conn);
面向对象:
plain 复制代码
$conn->close();

总结:

增、删、改 :使用 mysqli_query 执行操作,返回一个布尔值来判断是否成功。

查询 :使用 mysqli_query 执行 SELECT 查询,返回一个结果集,使用 mysqli_fetch_assocmysqli_fetch_row 解析结果。

面向对象和过程化 :可以选择面向过程(mysqli_*)或面向对象($conn->method)的方式来操作 MySQL。

注意: 在使用 mysqli_query 执行用户输入的 SQL 语句时,务必防止 SQL 注入攻击,推荐使用 预处理语句(Prepared Statements) 来确保安全。

相关推荐
想要入门的程序猿2 小时前
Qt菜单栏、工具栏、状态栏(右键)
开发语言·数据库·qt
键盘上的蚂蚁-2 小时前
Python 语言结合 Flask 框架来实现一个基础的代购商品管理
jvm·数据库·oracle
代码欢乐豆3 小时前
MongoDB的部署和操作
数据库·mongodb
<e^πi+1=0>3 小时前
使用Locust对MongoDB进行负载测试
数据库·mongodb
圆蛤镇程序猿3 小时前
【什么是MVCC?】
java·数据库·oracle
开心邮递员3 小时前
sql server: split 函数;cross apply操作符
数据库·sql
老大白菜3 小时前
PostgreSQL 内置函数
数据库·postgresql
Damon撇嘴笑3 小时前
Cause: java.sql.SQLException: sql injection violation, comment not allow异常问题处理
java·数据库·sql
山林竹笋3 小时前
Java解析PDF数据库设计文档
数据库·pdf
m0_748252234 小时前
万字详解 MySQL MGR 高可用集群搭建
android·mysql·adb