在信息发达的当今,数据安全的重要性不言而喻。比如:身份证,银行卡,名字,电话号码,地址都是重要又敏感的信息。在数据库系统中通过数据加密,以保障数据的安全性。目前软件行业常用的加密算法: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密码还可以用于文件完整性检查,可以检查文件是否被篡改。
实例:
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。
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_encrypto_mode='aes-256-cbc';
实例:
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在生成密钥时使用的迭代计数初始向量,用于块加密的模式.计数越高,对暴力攻击的抵抗力就越强,因为攻击者的计算成本越高,但密钥推导过程也必然如此
实例:
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作为十六进制的值。
组合使用方式:
mysql> SET @init_vector = RANDOM_BYTES(16);
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在密码学上更安全的等价。
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)。
#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语句的规范语句摘要。
实例
- 如下面WHERE ID赋值虽不一样,但最终的hash值是一样。
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)
- 把语句中的值,变量去掉,替换成?符号。类似于公用的语句。
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)
- 存储过程,函数都是支持的。
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)
-
max_digest_length变量确定函数可用于计算规范化语句摘要的最大字节数。
-
对于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