前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >【转】MySQL8.0 GA Encryption加密

【转】MySQL8.0 GA Encryption加密

作者头像
保持热爱奔赴山海
发布2024-09-30 11:47:29
1060
发布2024-09-30 11:47:29
举报
文章被收录于专栏:数据库相关

在信息发达的当今,数据安全的重要性不言而喻。比如:身份证,银行卡,名字,电话号码,地址都是重要又敏感的信息。在数据库系统中通过数据加密,以保障数据的安全性。目前软件行业常用的加密算法:MD5、SHA1、SHA2,AES、DES、CAST、IDEA、RC2、RC5 等。这些加密算法的目的在于使别人无法查看加密的数据,并且在需要的时候还可以对数据进行解密来重新查看数据。

在数据库方面,加密不光是隐藏敏感信息,还同时保证存储数据紧凑,不浪费空间。 是一举二得的功能。

MySQL在这方面提供:

  • MySQL Enterprise Data Masking ,Transparent Data Encryption,openssl_udf等方式为企业提供安全机制。
  • MySQL GA版本也提供通过加密函数,处理敏感数据的方式。 MD5、SHA,SHA1,SHA2,STATEMENT_DIGEST,STATEMENT_DIGEST_TEXT.

MySQL8.0提供的加密函数如下:

Name

Description

AES_ENCRYPT()

使用AES加密

AES_DECRYPT()

使用AES解密

MD5()

计算MD5校验值

RANDOM_BYTES()

返回随机字节量

SHA1(), SHA()

计算SHA-1 160位校验值

SHA2()

计算SHA-2校验值

STATEMENT_DIGEST()

计算语句摘要哈希值

STATEMENT_DIGEST_TEXT()

转换规范化语句摘要

MD5方式

MD5算法是一种哈希算法,也是常用的方式,但这一算法是不可逆的。也就是说,通过哈希算法得到的数据,无法经过任何算法还原回去。

底层处理方式是把数据转换成MD5或SHA1等,之后返回十六进制数字字符串的函数的值,则通过使用UNHEX将十六进制表示转换为二进制并将结果存储在binary(N)列中,可以获得更有效的存储和比较。

每对十六进制数字需要一个二进制形式的字节,因此需要十六进制字符串的长度。

  • 对于MD5值,N为16。
  • 对于SHA1值 N为20。
  • 对于SHA2值,N的范围从28到32。

使用场景方面: MD5最常用于加密用户密码,它可以将用户输入的明文密码转换成一个128位的散列值,这个散列值可以用来验证用户输入的密码是否正确,而不必将用户的密码明文存储在服务器上,从而保护用户的密码安全。此外,MD5密码还可以用于文件完整性检查,可以检查文件是否被篡改。

实例:

代码语言:javascript
复制
mysql> CREATE TABLE md5_tbl (md5_val_char CHAR(32),md5_val_bin BINARY(16));
Query OK, 0 rows affected (0.02 sec)

mysql> INSERT INTO md5_tbl (md5_val_char) VALUES(MD5('abcdef'));
Query OK, 1 row affected (0.01 sec)
mysql> INSERT INTO md5_tbl (md5_val_bin ) VALUES(UNHEX(MD5('abcdef'))) ;
Query OK, 1 row affected (0.00 sec)

mysql> SELECT * FROM md5_tbl;
+----------------------------------+------------------------------------+
| md5_val_char                     | md5_val_bin                        |
+----------------------------------+------------------------------------+
| e80b5017098950fc58aad83c8c14978e | NULL                               |
| NULL                             | 0xE80B5017098950FC58AAD83C8C14978E |
+----------------------------------+------------------------------------+

备注: 除非使用SSL连接,否则作为加密函数参数提供的密码或其他敏感值将以明文形式发送到MySQL服务器。此外,这些值会出现在所写入的任何MySQL日志。

MD5还是可以破解的。 可以把提交的MD5密码与lib库中的MD5密码进行比对,如果有相同的,就可以获取到正确的密码(穷举法)。目前最简单、常见的破解方式当属字典破解(Dictionary Attack)和暴力破解(Brute Force Attack)方式。这种方式非常耗时,效率比较低。还可以采用一种更高效的破解方式,查表法(Lookup Tables),逆向查表法(Reverse Lookup Tables)、彩虹表(Rainbow Tables)等

AES方式

在MySQL里官方使用AES(高级加密标准)算法对数据进行解密。提供AES_ENCRYPT和AES_DECRYPT函数。通过使用默认128位密钥长度实现AES。可以使用196或256位的密钥长度。长度是性能和安全性之间的权衡。

  • 在复制集群中使用AES_DECRYPT的语句对于基于statement语句的复制是不安全的。
  • 从MySQL 8.0.30开始,这些函数支持使用密钥派生函数(KDF)从key_str中传递的信息中创建一个加密的强密钥。派生密钥用于加密和解密数据,它保留在MySQL Server实例中,用户无法访问。强烈建议使用KDF,因为它比指定自己的预制密钥或在使用函数时通过更简单的方法派生密钥提供更好的安全性。
  • AES_ENCRYPT和AES_DECRYPT允许控制块加密模式。参数:block_encrypto_mode控制基于块的加密算法的模式。其默认值为aes-128-ecb,表示使用128位密钥长度和ecb模式进行加密。 允许的keylen值为128、192和256,允许的模式值为ECB、CBC、CFB1、CFB8、CFB128和OFB。
代码语言:javascript
复制
mysql> show variables like '%block_encryption_mode%';
+-----------------------+-------------+
| Variable_name         | Value       |
+-----------------------+-------------+
| block_encryption_mode | aes-128-ecb |
+-----------------------+-------------+
1 row in set (0.00 sec)

#AES加密函数使用256位的密钥长度和CBC模式
mysql> SET GLOBAL block_encryption_mode='aes-256-cbc';

实例:

代码语言:javascript
复制
AES_DECRYPT(crypt_str,key_str[,init_vector][,kdf_name][,salt][,info | iterations])

AES_ENCRYPT(str,key_str[,init_vector][,kdf_name][,salt][,info | iterations])
  • str -用于指定纯字符串。
  • crypt_str 加密字符串。
  • key_str -它用于指定用于加密str的String。经过加密和压缩的结果返回二进制字符,所以建议配置为VARBINARY或BLOB二进制字符串数据类型的列,防止字符集转换从而导致插入失败。
  • init_vector 初始向量,用于块加密的模式(block_encryption_mode)
  • kdf:密钥派生函数(KDF)的名称,用于根据传入key_str的输入密钥材料和KDF的其他参数创建密钥。支持HKDF(OpenSSL 1.1.0. HKDF),pbkdf2_hmac(OpenSSL 1.0.2. PBKDF2)
  • salt hash值存储在在数据库中依然是不够安全的。采取salt方式。就是一个随机生成的字符串。将盐与原始密码连接(concat)在一起(放在前面或后面都可以,对于密码可以这样处理,其他情况就不行。
  • iterations PBKDF2在生成密钥时使用的迭代计数初始向量,用于块加密的模式.计数越高,对暴力攻击的抵抗力就越强,因为攻击者的计算成本越高,但密钥推导过程也必然如此

实例:

代码语言:javascript
复制
mysql> CREATE TABLE aes_tbl (aes_val varchar(256)) ENGINE=InnoDB DEFAULT CHARSET=latin1 ;
Query OK, 0 rows affected (0.02 sec)

#加密插入
mysql> INSERT INTO aes_tbl VALUES(aes_encrypt('abcd','paw123456'));
Query OK, 1 row affected (0.00 sec)

mysql> SELECT * FROM aes_tbl;
+----------------------------+
| aes_val                    |
+----------------------------+
| ùpñU!㿧ҟWHƒôò           |
+----------------------------+
1 row in set (0.00 sec)

#AES_DECRYPT解密,秘钥错误返回NULL
mysql> SELECT AES_DECRYPT(aes_val,'123456')  FROM aes_tbl;
+-------------------------------+
| AES_DECRYPT(aes_val,'123456') |
+-------------------------------+
| NULL                          |
+-------------------------------+
1 row in set (0.00 sec)

mysql> SELECT AES_DECRYPT(aes_val,'paw123456')  FROM aes_tbl;
+----------------------------------------------------------+
| AES_DECRYPT(aes_val,'test')                              |
+----------------------------------------------------------+
| 0x62                                                     |
+----------------------------------------------------------+
1 row in set (0.00 sec)

RANDOM_BYTES

此函数返回使用SSL库的随机数生成器生成的len随机字节的二进制字符串。允许的len值范围为1到1024。对于超出该范围的值,将发生错误。如果len为NULL,则返回NULL。

  • RANDOM_BYTES可用于为AES_DECRYPT和AES_ENCRYPT函数提供初始化向量。若要在该上下文中使用,len必须至少为16。允许较大的值,但超过16的字节将被忽略。
  • RANDOM_BYTES生成一个随机值,使其结果不确定。因此,使用此函数的语句对于基于语句的复制是不安全的。
  • 如果从mysql客户机中调用RANDOM_BYTES,则二进制字符串将使用十六进制表示法显示,具体取决于–binary作为十六进制的值。

组合使用方式【推荐这种用法】:

代码语言:javascript
复制
mysql> SET @init_vector = RANDOM_BYTES(16);  -- 随机的salt
Query OK, 0 rows affected (0.00 sec)

mysql> SET @key = SHA2('secret key', 224);
Query OK, 0 rows affected (0.00 sec)

mysql> SET @crypto = AES_ENCRYPT('abcd', @key, @init_vector);
Query OK, 0 rows affected, 2 warnings (0.00 sec)

mysql> SELECT @crypto;
+------------------+
| @crypto          |
+------------------+
| ?¯rZªտXPÝdG2     |
+------------------+
1 row in set (0.00 sec)

mysql> SELECT AES_DECRYPT(@crypto, @key, @init_vector);
+-----------------------------------+
| AES_DECRYPT(@crypto, @key, @salt) |
+-----------------------------------+
| abcd                              |
+-----------------------------------+
1 row in set, 1 warning (0.00 sec)

HASH

计算字符串的SHA-1 160位校验.SHA与SHA1一样。可以被视为与MD5在密码学上更安全的等价。

代码语言:javascript
复制
mysql> SELECT SHA1('abc');
+------------------------------------------+
| SHA1('abc')                              |
+------------------------------------------+
| a9993e364706816aba3e25717850c26c9cd0d89d |
+------------------------------------------+
1 row in set (0.00 sec)

HASH2

计算SHA-2系列哈希函数(SHA-224、SHA-256、SHA-384和SHA-512)。

代码语言:javascript
复制
#1.这里第二个参数指示结果所需的比特长度,其值必须为224、256、384、512或0(相当于256)
mysql> SELECT SHA2('abc', 224);
+----------------------------------------------------------+
| SHA2('abc', 224)                                         |
+----------------------------------------------------------+
| 23097d223405d8228642a477bda255b32aadbce4bda0b3f7e36c9da7 |
+----------------------------------------------------------+
1 row in set (0.00 sec)


#2.如果参数为NULL或哈希长度不是允许的值之一,则返回值为NULL。
mysql> SELECT SHA2('abc', NULL);
+-------------------+
| SHA2('abc', NULL) |
+-------------------+
| NULL              |
+-------------------+
1 row in set, 1 warning (0.00 sec)

仅当MySQL配置了SSL支持时,此函数才起作用。SHA2可以被认为比MD5和SHA1更安全。

STATEMENT_DIGEST

语句摘要转换功能。ps库的events_statements_summary_by_digest表就是通过这个函数实现的。

  • STATEMENT_DIGEST: 给定SQL语句作为字符串,将语句摘要哈希值作为连接字符集中的字符串返回。就是说把一些条件赋予值,变量去掉,之后进行HASH处理。
  • STATEMENT_DIGEST_TEXT: 函数返回以字符串形式给定的SQL语句的规范语句摘要。

实例

  1. 如下面WHERE ID赋值虽不一样,但最终的hash值是一样。
代码语言:javascript
复制
mysql> SELECT STATEMENT_DIGEST("SELECT * FROM test WHERE ID=1;");
+------------------------------------------------------------------+
| STATEMENT_DIGEST("SELECT * FROM test WHERE ID=1;")               |
+------------------------------------------------------------------+
| c4af45cba988541e319888c1bd5d79db763895a68320e5cce65e3b7e8547f919 |
+------------------------------------------------------------------+
1 row in set (0.00 sec)

mysql> SELECT STATEMENT_DIGEST("SELECT * FROM test WHERE ID=5;");
+------------------------------------------------------------------+
| STATEMENT_DIGEST("SELECT * FROM test WHERE ID=5;")               |
+------------------------------------------------------------------+
| c4af45cba988541e319888c1bd5d79db763895a68320e5cce65e3b7e8547f919 |
+------------------------------------------------------------------+
1 row in set (0.00 sec)
  1. 把语句中的值,变量去掉,替换成?符号。类似于公用的语句。
代码语言:javascript
复制
mysql> select STATEMENT_DIGEST_TEXT("SELECT * FROM test WHERE ID=5;");
+---------------------------------------------------------+
| STATEMENT_DIGEST_TEXT("SELECT * FROM test WHERE ID=5;") |
+---------------------------------------------------------+
| SELECT * FROM `test` WHERE `ID` = ? ;                   |
+---------------------------------------------------------+
1 row in set (0.00 sec)

注意,这个STATEMENT_DIGEST_TEXT函数必须在任一个库里面执行,如果没有use切换到库里,会报错,如下:
[(none)]> select STATEMENT_DIGEST_TEXT("SELECT * FROM test WHERE ID=5;");
ERROR 3676 (HY000): Could not parse argument to digest function: "No database selected".

这个函数有点意思,基本上和 pt-fingerprint 的功能类似了。(实际测试了下,单线程下还是pt-fingerprint更快些)

如果我们只要在外面套一层md5就可以提取到指纹。
mysql> select md5(STATEMENT_DIGEST_TEXT("SELECT * FROM test WHERE ID=5;"));
+--------------------------------------------------------------+
| md5(STATEMENT_DIGEST_TEXT("SELECT * FROM test WHERE ID=5;")) |
+--------------------------------------------------------------+
| 46fd7000ad7d8b43806424d56ea0bc5a                             |
+--------------------------------------------------------------+
1 row in set (0.00 sec)
mysql> select md5(STATEMENT_DIGEST_TEXT("SELECT * FROM test WHERE ID=323;"));
+----------------------------------------------------------------+
| md5(STATEMENT_DIGEST_TEXT("SELECT * FROM test WHERE ID=323;")) |
+----------------------------------------------------------------+
| 46fd7000ad7d8b43806424d56ea0bc5a                               |
+----------------------------------------------------------------+
1 row in set (0.00 sec)
  1. 存储过程,函数都是支持的。
代码语言:javascript
复制
mysql> SELECT STATEMENT_DIGEST('CALL abc()');
+------------------------------------------------------------------+
| STATEMENT_DIGEST('CALL abc()')                                   |
+------------------------------------------------------------------+
| b356ecfb586e0a761b9794bcb6d2e4395d40416f3110e688084bd67e87d27ae9 |
+------------------------------------------------------------------+
1 row in set (0.00 sec)

mysql> SELECT STATEMENT_DIGEST('SELECT  abc()');
+------------------------------------------------------------------+
| STATEMENT_DIGEST('SELECT  abc()')                                |
+------------------------------------------------------------------+
| 0af0d93da64f52e740489a7bcd409469011ba78238c29facf60763264b64727e |
+------------------------------------------------------------------+
1 row in set (0.00 sec)

mysql> SELECT STATEMENT_DIGEST('SELECT  NOW()');
+------------------------------------------------------------------+
| STATEMENT_DIGEST('SELECT  NOW()')                                |
+------------------------------------------------------------------+
| 2fad55a506c3342fe82629447a3412f5dfb1aaaa20b13be45f1b9c42175da923 |
+------------------------------------------------------------------+
1 row in set (0.00 sec)
  1. max_digest_length变量确定函数可用于计算规范化语句摘要的最大字节数。
  2. 对于DIGEST_HASH函数 5.7无此函数,只有8.0才存在 。同时5.7和8.0使用的算法也不同。 源码sql\sql_digest.h DIGEST_HASH_TO_STRING_LENGTH函数里:

总结

网络时代,是信息极为丰富的时代,也是信息泡沫的泛滥,安全极度匮乏。数据库安全加密解密机制,不可缺少。除此之外,加密解密也是消耗一定的性能的,起码aes加解密性能损失大约10%~25%。 合理使用,才是DBA运营之道。

参考

https://dev.mysql.com/doc/refman/8.0/en/encryption-functions.html

本文系转载,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文系转载前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • MD5方式
  • AES方式
  • RANDOM_BYTES
  • HASH
  • HASH2
  • STATEMENT_DIGEST
  • 总结
  • 参考
相关产品与服务
云数据库 MySQL
腾讯云数据库 MySQL(TencentDB for MySQL)为用户提供安全可靠,性能卓越、易于维护的企业级云数据库服务。其具备6大企业级特性,包括企业级定制内核、企业级高可用、企业级高可靠、企业级安全、企业级扩展以及企业级智能运维。通过使用腾讯云数据库 MySQL,可实现分钟级别的数据库部署、弹性扩展以及全自动化的运维管理,不仅经济实惠,而且稳定可靠,易于运维。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档