| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| VALIDATE_PASSWORD_STRENGTH() | |
许多加密和压缩函数返回的字符串的结果可能包含任意字节的值。如果希望存储这些结果,请使用 VARBINARY 或 BLOB 二进制字符串数据类型的列。这避免了可能会改变数据值的尾随空格或字符集转换的潜在问题,比如使用非二进制字符串数据类型(CHAR、VARCHAR、TEXT)时可能发生的问题。一些加密函数返回 ASCII 字符字符串:MD5(),SHA(),SHA1(),SHA2(),STATEMENT_DIGEST(), STATEMENT_DIGEST_TEXT()。它们的返回值是一个字符串,该字符串具有由 character_set_connection 和 collation_connection 系统变量决定的字符集和排序规则。这是非二进制字符串,除非字符集是 binary。如果应用程序存储 MD5() 或 SHA1() 等返回十六进制数字字符串函数的值,可以通过使用 UNHEX() 将十六进制表示转换为二进制并将结果存储在 BINARY(N) 列中,从而获得更有效的存储和进行比较。每一对十六进制数字表示成二进制形式需要一个字节,所以 N 的值取决于十六进制字符串的长度。对于 MD5() 值,N 为 16,对于 SHA1() 值 N 为 20。对于 SHA2(),N 的范围是 28 到 32,具体取决于参数指定的对结果的期望位长。在 CHAR 列中存储十六进制字符串的空间消耗至少为2倍,如果值存储在使用utf8字符集的列中(其中每个字符使用4个字节),则最多为8倍。存储字符串还会导致比较较缓慢,因为值较大,并且需要考虑字符集排序规则。假设应用程序在 CHAR(32) 列中存储 MD5() 字符串值:CREATE TABLE md5_tbl (md5_val CHAR(32), ...);
INSERT INTO md5_tbl (md5_val, ...) VALUES(MD5('abcdef'), ...);
要将十六进制字符串转换为更紧凑的形式,请修改应用程序,使用 UNHEX() 和 BINARY(16),如下所示:CREATE TABLE md5_tbl (md5_val BINARY(16), ...);
INSERT INTO md5_tbl (md5_val, ...) VALUES(UNHEX(MD5('abcdef')), ...);
应用程序应该准备好处理非常罕见的情况,即哈希函数为两个不同的输入值生成相同的值。一种检测冲突的方法是使哈希列成为主键。对MD5和SHA-1算法的利用已经为人所知。您可能希望考虑使用本节中描述的其他单向加密函数,例如 SHA2()。除非使用SSL连接,否则作为参数提供给加密函数的密码或其他敏感值将以明文形式发送到 MySQL 服务器。同样,这些值也会出现在所写入的任何 MySQL 日志中。为了避免这类情况信息的暴露,应用程序可以在将敏感值发送到服务器之前在客户端加密它们。同样的考虑也适用于加密密钥。为了避免公开这些值,应用程序可以使用存储过程在服务器端对值进行加密和解密。● AES_DECRYPT(crypt_str,key_str[,init_vector])该函数使用官方的 AES(高级加密标准)算法解密数据。使用 AES_DECRYPT() 的语句对于基于语句的复制是不安全的。● AES_ENCRYPT(str,key_str[,init_vector])AES_ENCRYPT() 和 AES_DECRYPT() 使用官方 AES(高级加密标准)算法实现数据的加密和解密,以前称为 “Rijndael”。AES 标准允许不同的密钥长度。默认情况下,这些函数实现 128 位密钥长度的 AES。如后面所述,可以使用 196 位或 256 位的密钥长度。密钥长度是性能和安全性之间的一种权衡。AES_ENCRYPT() 使用密钥字符串 key_str 加密字符串 str,并返回一个包含加密输出的二进制字符串。AES_DECRYPT() 使用密钥字符串 key_str 解密加密的字符串 crypt_str,并返回原始明文字符串。如果任一函数参数为 NULL,则函数返回 NULL。str 和 crypt_str 参数可以是任意长度,并且会自动填充 str,使其是基于块的算法(如AES)所要求的块的倍数。这个填充由 AES_DECRYPT() 函数自动删除。crypt_str 的长度可以通过以下公式计算:16 * (trunc(string_length 16) + 1)
对于 128 位的密钥长度,将密钥传递给 key_str 参数的最安全方法是创建一个真正随机的128位值,并将其作为二进制值传递。例如:INSERT INTO t
VALUES (1,AES_ENCRYPT('text',UNHEX('F3229A0B371ED2D9441B830D21A390C3')));
INSERT INTO t
VALUES (1,AES_ENCRYPT('text', UNHEX(SHA2('My secret passphrase',512))));
不要直接将密码或密码短语传递给 crypt_str,先对其进行哈希求值。本文档的以前版本建议使用前一种方法,但现在不再推荐使用,因为这里显示的示例更安全。如果 AES_DECRYPT() 检测到无效数据或不正确的填充,它将返回 NULL。但是,如果输入数据或密钥无效,则 AES_DECRYPT() 可能返回一个非 NULL 值(可能是垃圾值)。AES_ENCRYPT() 和 AES_DECRYPT() 允许控制块加密模式,并接受一个可选的 init_vector 初始化向量参数:■ block_encryption_mode 系统变量控制基于块的加密算法的模式。默认值为 aes-128-ecb,表示采用128位密钥长度的ECB模式加密。■ 可选的 init_vector 参数为需要它的块加密模式提供了一个初始化向量。对于需要可选 init_vector 参数的模式,它必须为16字节或更长的字节(超过16的字节将被忽略)。如果缺少 init_vector,则会发生错误。对于不需要 init_vector 的模式,如果指定了 init_vector,则忽略它并生成警告。可以通过调用 RANDOM_BYTES(16) 生成用于初始化向量的随机字节字符串。对于需要初始化向量的加密模式,必须使用相同的向量进行加密和解密。mysql> SET block_encryption_mode = 'aes-256-cbc';
mysql> SET @key_str = SHA2('My secret passphrase',512);
mysql> SET @init_vector = RANDOM_BYTES(16);
mysql> SET @crypt_str = AES_ENCRYPT('text',@key_str,@init_vector);
mysql> SELECT AES_DECRYPT(@crypt_str,@key_str,@init_vector);
+-----------------------------------------------+
| AES_DECRYPT(@crypt_str,@key_str,@init_vector) |
+-----------------------------------------------+
| text |
+-----------------------------------------------+
下表列出了允许的块加密模式以及是否需要初始化向量参数。使用 AES_ENCRYPT() 或 AES_DECRYPT() 的语句对于基于语句的复制是不安全的。如果从 mysql 客户端中调用 AES_ENCRYPT(),则二进制字符串将使用十六进制表示法显示,具体取决于 --binary-as-hex 的值。https://dev.mysql.com/doc/refman/8.0/en/encryption-functions.html