本文链接已迁移到: /posts/Mysql的字符编码的大坑

Mysql的UTF8与UTF8mb4


由于某个神秘项目的需要,出现了一个导入上亿条 utf8 数据到 mysql 5.7 中的需求,在实际使用的过程中,我发现 node 在向数据库中写入中文数据时会出现类似下面的报错

failed: Error: Incorrect string value: '\\xC4\\x83ri' for column 'name' at row 1

于是我猜测是字符编码的问题,于是就将编码全都改成了 utf8,但尝试过后还是存在这个报错,遂上 stackoverflow 学习了以下前人的经验,发现了一篇文章 How to support full Unicode in MySQL databases · Mathias Bynens 这里详细讲解了 mysql 中 utf8 编码的问题,并且指出 mysql 中推荐一直使用完整的 utf8mb4 编码,这里对文章做了一个翻译

修改库、表、列

  • 数据库名
ALTER DATABASE 库 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci;
  • 表名
ALTER TABLE 表 CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
  • 列名
ALTER TABLE 表 CHANGE 列1 列2 VARCHAR(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;

修改配置文件

[client]  
default-character-set = utf8mb4  
  
[mysql]  
default-character-set = utf8mb4  
  
[mysqld]  
character-set-server = utf8mb4  
collation-server = utf8mb4_unicode_ci

然后重启服务

sudo service mysql restart

检查更改结果

最终的修改结果应该如下所示,注意其中只有系统编码还是 utf8

mysql> SHOW VARIABLES WHERE Variable_name LIKE 'character_set_%' OR Variable_name LIKE 'collation%';
+--------------------------+--------------------+
| Variable_name            | Value              |
+--------------------------+--------------------+
| character_set_client     | utf8mb4            |
| character_set_connection | utf8mb4            |
| character_set_database   | utf8mb4            |
| character_set_filesystem | binary             |
| character_set_results    | utf8mb4            |
| character_set_server     | utf8mb4            |
| character_set_system     | utf8               |
| collation_connection     | utf8mb4_unicode_ci |
| collation_database       | utf8mb4_unicode_ci |
| collation_server         | utf8mb4_unicode_ci |
+--------------------------+--------------------+
10 rows in set (0.00 sec)

思考

由于 mysql 并没有对 utf8mb4 编码进行大力推荐使用,导致现在很多的项目还在使用不完整的 utf8 编码,这里我就联想到了 mysql 中 GBK 编码存在的宽字节注入

宽字节注入:因为字符集不同 躲过 SQL 注入过滤函数 addslashes() 使 addslashes 过滤的单引号、双引号、反斜杠、NULL可以利用,从而绕过SQL注入防护达成SQL注入

也是因为字符集不统一造成的逃逸,这里的 utf8 虽然我还没有看到相关的文章对其进行利用,不过这里显然是存在安全风险的,特别是对于中文站点,自我感觉容易造成二次注入,所以要注意以后使用 mysql 的时候一定要规避 utf8 编码,全部换成 utf8mb4,也不差那一字节的空间。

参考

- The End -