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 及之后版本的默认字符集。

相关推荐
InnovatorX1 小时前
Linux 下 MySQL 8 搭建教程
linux·mysql·adb
Lyyaoo.2 小时前
MySQL数据库知识总结
数据库·mysql
计算机学姐4 小时前
基于Asp.net的医院病历管理系统
vue.js·vscode·后端·mysql·sqlserver·c#·asp.net
计算机学姐4 小时前
基于Asp.net的汽车租赁管理系统
vue.js·后端·mysql·sqlserver·c#·汽车·asp.net
失业写写八股文4 小时前
数据库死锁场景如何复现和解决?
数据库·mysql
littlegirll6 小时前
同步Oracle及mysql至KADB的KFS配置文件参考
数据库·mysql·oracle
Eugene Jou6 小时前
FlinkSQL实现实时同步和实时统计过程(MySQL TO MySQL)
数据库·mysql·flink·flinksql
编程零零七6 小时前
基于Python+Flask+MySQL+HTML的爬取豆瓣电影top-250数据并进行可视化的数据可视化平台
python·mysql·信息可视化·flask·python教程·python安装
xjz18428 小时前
MySQL锁机制全解:记录锁、间隙锁、邻键锁的原理与实战
mysql