MySQL知识点

什么是 SQL 注入?

SQL 注入就是在用户输入的字符串中加入 SQL 语句,如果在设计不良的程序中忽略了检查,那么这些注入进去的 SQL 语句就会被数据库服务器误认为是正常的 SQL 语句而运行,攻击者就可以执行计划外的命令或访问未被授权的数据。

SQL注入的原理

SQL 注入的原理主要有以下 4 点:

1.恶意拼接查询

我们知道,SQL 语句可以查询、插入、更新和删除数据,且使用分号来分隔不同的命令。例如:

SELECT * FROM users WHERE user_id = $user_id

其中,user_id 是传入的参数,如果传入的参数值为"1234; DELETE FROM users",那么最终的查询语句会变为:

SELECT * FROM users WHERE user_id = 1234; DELETE FROM users

如果以上语句执行,则会删除 users 表中的所有数据。

2.利用注释执行非法命令

SQL 语句中可以插入注释。例如:

SELECT COUNT(*) AS 'num' FROM game_score WHERE game_id=24411 AND version=$version

如果 version 包含了恶意的字符串'-1' OR 1 AND SLEEP(500)--,那么最终查询语句会变为:

SELECT COUNT(*) AS 'num' FROM game_score WHERE game_id=24411 AND version='-1' OR 1 AND SLEEP(500)--

攻击者意图:

检测 SQL 注入漏洞 :攻击者通过构造 OR 3 AND SLEEP(500) 这样的条件,试图让数据库执行 SLEEP(500) 函数。如果数据库执行了 SLEEP(500),说明目标存在 SQL 注入漏洞。

延迟响应SLEEP(500) 会让数据库休眠 500 秒,导致应用程序的响应时间显著增加。攻击者可以通过观察响应时间来判断是否存在漏洞。

3.传入非法参数

SQL 语句中传入的字符串参数是用单引号引起来的,如果字符串本身包含单引号而没有被处理,那么可能会篡改原本 SQL 语句的作用。 例如:

SELECT * FROM user_name WHERE user_name = $user_name

如果 user_name 传入参数值为 G'chen,那么最终的查询语句会变为:

SELECT * FROM user_name WHERE user_name ='G'chen'

字符串 'G'chen' 中的单引号没有正确转义,导致 SQL 解析器认为字符串在 'G' 处结束,而 chen' 是多余的语法。如果用户输入 ' OR '1'='1,则 SQL 语句变为:

SELECT * FROM user_name WHERE user_name = '' OR '1'='1'

WHERE 条件变为 user_name = '' OR '1'='1',这是一个恒真条件。数据库会返回 user_name 表中的所有数据,导致信息泄露。

4.添加额外条件

在 SQL 语句中添加一些额外条件,以此来改变执行行为。条件一般为真值表达式。例如:

UPDATE users SET userpass='userpass' WHERE user_id=user_id;

如果 user_id 被传入恶意的字符串"1234 OR TRUE",那么最终的 SQL 语句会变为:

UPDATE users SET userpass= '123456' WHERE user_id=1234 OR TRUE;

这将更改所有用户的密码。

避免SQL注入

1. 过滤输入内容,校验字符串

过滤输入内容就是在数据提交到数据库之前,就把用户输入中的不合法字符剔除掉。可以使用编程语言提供的处理函数或自己的处理函数来进行过滤,还可以使用正则表达式匹配安全的字符串。

如果值属于特定的类型或有具体的格式,那么在拼接 SQL 语句之前就要进行校验,验证其有效性。比如对于某个传入的值,如果可以确定是整型,则要判断它是否为整型,在浏览器端(客户端)和服务器端都需要进行验证。

2. 参数化查询

参数化查询目前被视作是预防 SQL 注入攻击最有效的方法。参数化查询是指在设计与数据库连接并访问数据时,在需要填入数值或数据的地方,使用参数来给值。

MySQL 的参数格式是以"?"字符加上参数名称而成,如下所示:

UPDATE myTable SET c1 = ?c1, c2 = ?c2, c3 = ?c3 WHERE c4 = ?c4

在使用参数化查询的情况下,数据库服务器不会将参数的内容视为 SQL 语句的一部分来进行处理,而是在数据库完成 SQL 语句的编译之后,才套用参数运行。因此就算参数中含有破坏性的指令,也不会被数据库所运行。

使用预编译的SQL语句语义不会发生改变,在SQL语句中,变量用问号?表示,黑客即使本事再大,也无法改变SQL语句的结构。简单总结,参数化能防注入的原因在于,语句是语句,参数是参数,参数的值并不是语句的一部分,数据库只按语句的语义跑,至于跑的时候是带一个普通背包还是一个怪物,不会影响行进路线。

3. 安全测试、安全审计

除了开发规范,还需要合适的工具来确保代码的安全。我们应该在开发过程中应对代码进行审查,在测试环节使用工具进行扫描,上线后定期扫描安全漏洞。通过多个环节的检查,一般是可以避免 SQL 注入的。

下面是在开发过程中可以避免 SQL 注入的一些方法。

1. 避免使用动态SQL

避免将用户的输入数据直接放入 SQL 语句中,最好使用准备好的语句和参数化查询,这样更安全。

在 MySQL 中,可以使用 PREPAREEXECUTEDEALLOCATE PREPARE 语句实现参数化查询。

sql 复制代码
-- 准备 SQL 语句
PREPARE stmt FROM 'SELECT * FROM users WHERE username = ? AND password = ?';

-- 绑定参数
SET @username = 'admin';
SET @password = 'password123';

-- 执行 SQL 语句
EXECUTE stmt USING @username, @password;

-- 释放预处理语句
DEALLOCATE PREPARE stmt;

2. 不要将敏感数据保留在纯文本中

加密存储在数据库中的私有/机密数据,这样可以提供了另一级保护,以防攻击者成功地排出敏感数据。

3. 限制数据库权限和特权

将数据库用户的功能设置为最低要求;这将限制攻击者在设法获取访问权限时可以执行的操作。

4. 避免直接向用户显示数据库错误

攻击者可以使用这些错误消息来获取有关数据库的信息。

SQL 预编译?

1.预编译语句是什么?

通常我们的一条sql在db接受到最终执行完毕返回可以分为三个过程:词法和语法解析;优化sql语句,制定执行计划;执行并返回结果。

但是很多情况,我们的一条sql语句可能会反复执行,或者每次执行的时候只有个别的值不同(比如query的where子句值不同,update的set子句值不同,insert的values值不同)。如果每次都需要经过上面的词法和语法解析、制定执行计划等,则效率就明显不行了。

所谓预编译语句就是将这类语句中的值用占位符替代,可以视为将sql语句模板化或者参数化,一般称这类语句叫 Prepared Statements 或者 Parameterized Statements。预编译语句的优势归纳为:一次编译、多次运行,省去了解析优化等过程;此外预编译语句能防止 sql 注入。

2.预编译语句

(1)建一张测试表 t

sql 复制代码
Create Table: CREATE TABLE `t` (
  `a` int(11) DEFAULT NULL,
  `b` varchar(20) DEFAULT NULL,
  UNIQUE KEY `ab` (`a`,`b`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8

(2)编译

通过 PREPARE stmt_name FROM perpare_stm 的语法来预编译一条 sql 语句

sql 复制代码
PREPARE  ins FROM 'INSERT INTO t VALUES (?,?)';

(3)执行

通过 EXECUTE stmt_name [USING @var_name [,@var_name]...]的语法来执行预编译语句

sql 复制代码
SET @a=999,@b='hello';
EXECUTE ins USING @a,@b;

此时数据已经插入。

MySQL中的预编译语句作用域是会话级,但可以通过 max_prepared_stmt_count 变量来控制全局最大的存储的预编译语句数量:

sql 复制代码
SET @@global.max_prepared_stmt_count=1;
/*此时设置预编译最大条数为1,如果继续使用预编译,就会报错*/

(4)释放

如果我们想要释放一条预编译语句,则可以使用{DEALLOCATE | DROP} PREPARE stmt_name的语法进行操作:

sql 复制代码
 DEALLOCATE prepare ins;

拷贝表的几种方式?

方式一:拷贝表结构,但是没有数据

create table 表1 like 表2;

方式二:拷贝数据,但是不会有主键和索引

create table 表1 as(select * from 表2);

方式三:又要有表结构,又要有数据

create table 表1 like 表2; insert into 表1 select * from 表2;

方式四:假如你想要一部分数据

insert into 表1 (select * from 表2 where 条件);

什么是水平分表与垂直分表?

水平分表垂直分表 是数据库分表的两种常见策略,用于解决单表数据量过大导致的性能问题。它们的主要区别在于数据的分割方式:

水平分表

水平分表是指将一张表中的数据 按行 分割到多个结构相同的表中。每个表存储一部分数据,所有表的表结构完全相同。

特点

  • 按行分割:将表中的数据按某种规则(如范围、哈希、列表等)分配到多个表中。

  • 表结构相同:所有分表的表结构完全相同

适用场景

  • 单表数据量过大,导致查询、插入、更新等操作变慢。

  • 例如,按时间范围(如按月、按年)或用户 ID 范围分表。

示例 :假设有一张用户表 user,数据量过大,可以按用户 ID 的范围进行水平分表:

  • user_0:存储 user_id 在 1-10000 的用户。

  • user_1:存储 user_id 在 10001-20000 的用户。

  • user_2:存储 user_id 在 20001-30000 的用户。

优点

  • 减少单表数据量,提高查询性能。

  • 易于扩展,可以通过增加分表来支持更多数据。

缺点

  • 需要维护分表规则,查询时需要确定数据位于哪个分表。

  • 跨分表的查询和聚合操作较复杂。

垂直分表

垂直分表是指将一张表中的数据 按列 分割到多个表中。每个表存储一部分列,所有表共享相同的主键。

特点

  • 按列分割:将表中的列按业务逻辑或访问频率分配到多个表中。

  • 共享主键:所有分表共享相同的主键,用于关联数据。

适用场景

  • 表中包含大量列,但每次查询只访问部分列。

  • 例如,将常用列和不常用列分开存储。

示例

假设有一张用户表 user,包含以下列:

  • user_idusernameemailpasswordaddressphonecreated_at

可以将表垂直分表为:

  • user_basic:存储 user_idusernameemailpassword

  • user_profile:存储 user_idaddressphonecreated_at

优点

  • 减少单表的列数,提高查询性能。

  • 按需加载数据,减少 I/O 开销。

缺点

  • 查询时需要关联多个表,增加查询复杂度。

  • 需要维护表之间的关系。

场景题

mysql 一张表可以有多少行数据?

SQL 语句的执行顺序?

  • **FROM 子句:**首先,SQL 查询会从 FROM 子句中指定的表中获取数据。如果涉及多个表,会计算这些表的笛卡尔积。
  • **ON 筛选器:**如果查询中包含 JOIN 操作,ON 子句会用于筛选 JOIN 条件匹配的行。
  • **JOIN 操作:**根据 JOIN 类型(如 INNER JOIN、LEFT JOIN 等),将符合条件的行组合在一起。
  • **WHERE 子句:**对 FROM 和 JOIN 后的结果集进行筛选,只保留满足 WHERE 条件的行。
  • **GROUP BY 子句:**将数据按指定的列进行分组,通常用于聚合操作。
  • 聚合函数计算:对每个分组应用聚合函数(如 COUNT、SUM、AVG 等)进行计算。
  • **HAVING 子句:**对分组后的结果进行二次筛选,只保留满足 HAVING 条件的分组。
  • **SELECT 子句:**选择要返回的列或表达式。
  • **DISTINCT 关键字:**去除结果集中的重复行。
  • **ORDER BY 子句:**对最终的结果集进行排序。
  • **LIMIT:**查询指定范围

MySQL 字符集?

1.MySQL 默认字符集

  • MySQL 5.7 及之前版本 :默认字符集是 latin1,这是一种单字节字符集,主要支持西欧语言。

  • MySQL 8.0 及之后版本 :默认字符集是 utf8mb4,这是一种多字节字符集,支持更广泛的字符范围,包括表情符号(Emoji)。

2.MySQL常用字符集及特点

以下是 MySQL 中常用的字符集及其特点:

1. latin1

  • 特点

    • 单字节字符集,支持西欧语言。

    • 存储空间小,但不支持多语言。

  • 使用场景

    • 仅需支持西欧语言的应用程序。

2. utf8

  • 特点

    • 多字节字符集,支持大部分 Unicode 字符。

    • 不支持 4 字节的 Unicode 字符(如表情符号)。

  • 使用场景

    • 需要支持多语言的应用程序,但不包括表情符号。

3. utf8mb4

  • 特点

    • 多字节字符集,支持完整的 Unicode 字符,包括表情符号。

    • 是 MySQL 8.0 及之后版本的默认字符集。

  • 使用场景

    • 需要支持多语言和表情符号的应用程序。

4. gbk

  • 特点

    • 双字节字符集,支持简体中文。

    • 存储空间较小,但不支持其他语言的字符。

  • 使用场景

    • 仅需支持简体中文的应用程序。

5. big5

  • 特点

    • 双字节字符集,支持繁体中文。

    • 存储空间较小,但不支持其他语言的字符。

  • 使用场景

    • 仅需支持繁体中文的应用程序。

3.什么是 Unicode 编码?

Unicode 编码 是一种字符编码标准,旨在支持全球所有语言的字符。Unicode 编码的字节数取决于具体的编码方式(如 UTF-8、UTF-16、UTF-32)。以下是常见的 Unicode 编码方式及其字节数的详细说明:

  1. UTF-8
  • 特点

    • 可变长度编码,每个字符占用 1 到 4 个字节。

    • 兼容 ASCII,ASCII 字符(0-127)仍占用 1 个字节。

  • 字节数

    • 1 字节:ASCII 字符(0-127)。

    • 2 字节:大部分拉丁字母、希腊字母、西里尔字母等。

    • 3 字节:大部分常用汉字、日文、韩文等。

    • 4 字节:不常用的字符、表情符号(Emoji)等。

示例

  • 字符 A(ASCII):1 字节。

  • 字符 ä(拉丁字母):2 字节。

  • 字符 (汉字):3 字节。

  • 字符 😊(表情符号):4 字节。

  1. UTF-16
  • 特点

    • 可变长度编码,每个字符占用 2 或 4 个字节。

    • 基本多语言平面(BMP)中的字符占用 2 个字节,其他字符占用 4 个字节。

  • 字节数

    • 2 字节:基本多语言平面(BMP)中的字符(如大部分常用汉字、拉丁字母等)。

    • 4 字节:辅助平面中的字符(如不常用的汉字、表情符号等)。

示例

  • 字符 A(ASCII):2 字节。

  • 字符 (汉字):2 字节。

  • 字符 😊(表情符号):4 字节。

  1. UTF-32
  • 特点

    • 固定长度编码,每个字符占用 4 个字节。

    • 简单但存储空间较大。

  • 字节数

    • 4 字节:所有字符。

示例

  • 字符 A(ASCII):4 字节。

  • 字符 (汉字):4 字节。

  • 字符 😊(表情符号):4 字节。

总结

编码方式 字节数 特点
UTF-8 1 到 4 字节 可变长度,兼容 ASCII,存储空间较小,适合网络传输和存储。
UTF-16 2 或 4 字节 可变长度,适合需要处理大量非 ASCII 字符的场景。
UTF-32 4 字节 固定长度,简单但存储空间较大,适合需要快速随机访问字符的场景。

4.MySQL 中的 Unicode 编码

  • utf8

    • 支持 1 到 3 字节的 Unicode 字符,不支持 4 字节的字符(如表情符号)。
  • utf8mb4

    • 支持 1 到 4 字节的 Unicode 字符,包括表情符号。

    • 是 MySQL 8.0 及之后版本的默认字符集。

相关推荐
梁萌24 分钟前
mysql使用事件做日志表数据转移
数据库·mysql
lThE ANDE26 分钟前
MySQL中的TRUNCATE TABLE命令
数据库·mysql
STER labo1 小时前
mysql配置环境变量——(‘mysql‘ 不是内部或外部命令,也不是可运行的程序 或批处理文件解决办法)
数据库·mysql·adb
dreamZhanglx1 小时前
MySQL进阶
数据库·mysql
xmjd msup1 小时前
MySQL 函数
数据库·mysql
jefl jxak2 小时前
mysql用户名怎么看
数据库·mysql
unDl IONA2 小时前
mysql之如何获知版本
数据库·mysql
俺不要写代码2 小时前
数据库:约束
数据库·mysql
WL_Aurora3 小时前
MySQL 5 卸载到 MySQL 8 安装完整指南(不踩坑版)
数据库·mysql
灰阳阳3 小时前
MySQL的基本架构
数据库·mysql·架构