文件首頁
MySQL 8.4 參考手冊
相關文件 下載本手冊
PDF (美式信紙) - 39.9Mb
PDF (A4) - 40.0Mb
Man Pages (TGZ) - 258.5Kb
Man Pages (Zip) - 365.5Kb
Info (Gzip) - 4.0Mb
Info (Zip) - 4.0Mb


MySQL 8.4 參考手冊  /  函數與運算子  /  加密與壓縮函數

14.13 加密與壓縮函數

表 14.18 加密函數

名稱 說明
AES_DECRYPT() 使用 AES 解密
AES_ENCRYPT() 使用 AES 加密
COMPRESS() 以二進位字串傳回結果
MD5() 計算 MD5 檢查總和
RANDOM_BYTES() 傳回隨機位元組向量
SHA1()SHA() 計算 SHA-1 160 位元檢查總和
SHA2() 計算 SHA-2 檢查總和
STATEMENT_DIGEST() 計算陳述式摘要雜湊值
STATEMENT_DIGEST_TEXT() 計算正規化的陳述式摘要
UNCOMPRESS() 解壓縮壓縮的字串
UNCOMPRESSED_LENGTH() 傳回壓縮前字串的長度
VALIDATE_PASSWORD_STRENGTH() 判斷密碼強度

許多加密與壓縮函數會傳回可能包含任意位元組值的字串。如果您想要儲存這些結果,請使用具有 VARBINARYBLOB 二進位字串資料類型的欄位。這可以避免尾隨空格移除或字元集轉換的潛在問題,這些問題會變更資料值,例如如果您使用非二進位字串資料類型 (CHARVARCHARTEXT)。

有些加密函數會傳回 ASCII 字元字串:MD5()SHA()SHA1()SHA2()STATEMENT_DIGEST()STATEMENT_DIGEST_TEXT()。它們的傳回值是具有字元集和定序的字串,由 character_set_connectioncollation_connection 系統變數決定。除非字元集為 binary,否則這是一個非二進位字串。

如果應用程式儲存來自函數(例如 MD5()SHA1())的值,這些函數會傳回十六進位數字的字串,則可以透過使用 UNHEX() 將十六進位表示法轉換為二進位,並將結果儲存在 BINARY(N) 欄位中,來獲得更有效率的儲存和比較。每對十六進位數字需要一個二進位形式的位元組,因此 N 的值取決於十六進位字串的長度。N 對於 MD5() 值為 16,對於 SHA1() 值為 20。對於 SHA2()N 的範圍從 28 到 32,取決於指定結果所需位元長度的引數。

CHAR 欄位中儲存十六進位字串的大小損失至少為兩倍,如果該值儲存在使用 utf8mb4 字元集的欄位中,則最多可達八倍(其中每個字元使用 4 個位元組)。儲存字串也會導致較慢的比較,因為值較大,而且需要考慮字元集定序規則。

假設應用程式將 MD5() 字串值儲存在 CHAR(32) 資料欄中

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][,kdf_name][,salt][,info | iterations])

    此函數使用官方 AES(進階加密標準)演算法解密資料。如需更多資訊,請參閱 AES_ENCRYPT() 的說明。

    使用 AES_DECRYPT() 的陳述式對於基於陳述式的複寫是不安全的。

  • AES_ENCRYPT(str,key_str[,init_vector][,kdf_name][,salt][,info | iterations])

    AES_ENCRYPT()AES_DECRYPT() 使用官方 AES(進階加密標準)演算法(先前稱為 Rijndael)實作資料的加密和解密。AES 標準允許各種金鑰長度。預設情況下,這些函數使用 128 位元金鑰長度實作 AES。可以使用 196 或 256 位元的金鑰長度,如下所述。金鑰長度是效能和安全性之間的權衡。

    AES_ENCRYPT() 使用金鑰字串 key_str 加密字串 str,並傳回包含加密輸出的二進位字串。AES_DECRYPT() 使用金鑰字串 key_str 解密加密字串 crypt_str,並以十六進位格式傳回原始(二進位)字串。(若要以純文字取得字串,請將結果轉換為 CHAR。或者,啟動 mysql 用戶端,並使用 --skip-binary-as-hex,使所有二進位值都顯示為文字。)如果任一函數引數為 NULL,則函數傳回 NULL。如果 AES_DECRYPT() 偵測到無效資料或不正確的填補,則會傳回 NULL。但是,如果輸入資料或金鑰無效,AES_DECRYPT() 有可能傳回非 NULL 值(可能是垃圾資料)。

    這些函數支援使用金鑰衍生函數 (KDF) 從 key_str 中傳遞的資訊建立密碼強金鑰。衍生金鑰用於加密和解密資料,並且它會保留在 MySQL 伺服器執行個體中,使用者無法存取。強烈建議使用 KDF,因為它比指定您自己的預製金鑰或在使用函數時透過更簡單的方法衍生金鑰提供更好的安全性。這些函數支援 HKDF(可從 OpenSSL 1.1.0 取得),您可以指定選用的鹽和特定於內容的資訊以包含在金鑰材料中,以及 PBKDF2(可從 OpenSSL 1.0.2 取得),您可以指定選用的鹽並設定用於產生金鑰的迭代次數。

    AES_ENCRYPT()AES_DECRYPT() 允許控制區塊加密模式。block_encryption_mode 系統變數控制基於區塊的加密演算法的模式。其預設值為 aes-128-ecb,表示使用 128 位元金鑰長度和 ECB 模式進行加密。如需此變數允許值的說明,請參閱第 7.1.8 節「伺服器系統變數」。選用的 init_vector 引數用於為需要它的區塊加密模式提供初始化向量。

    使用 AES_ENCRYPT()AES_DECRYPT() 的陳述式對於基於陳述式的複寫是不安全的。

    如果從 mysql 用戶端中叫用 AES_ENCRYPT(),則會根據 --binary-as-hex 的值,使用十六進位標記法顯示二進位字串。如需該選項的詳細資訊,請參閱第 6.5.1 節「mysql — MySQL 命令列用戶端」

    AES_ENCRYPT()AES_DECRYPT() 函數的引數如下

    str

    AES_ENCRYPT() 使用金鑰字串 key_str 或從指定的 KDF 衍生出的金鑰來加密的字串。字串可以是任何長度。系統會自動將填補新增至 str,使其為區塊的倍數(如 AES 等基於區塊的演算法所要求)。此填補會由 AES_DECRYPT() 函數自動移除。

    crypt_str

    AES_DECRYPT() 使用金鑰字串 key_str 或從指定的 KDF 衍生出的金鑰來解密的加密字串。字串可以是任何長度。可以使用此公式從原始字串的長度計算 crypt_str 的長度

    16 * (trunc(string_length / 16) + 1)
    key_str

    加密金鑰,或用作使用金鑰衍生函數 (KDF) 衍生金鑰基礎的輸入金鑰材料。對於相同的資料執行個體,請將相同的 key_str 值用於使用 AES_ENCRYPT() 加密和使用 AES_DECRYPT() 解密。

    如果您使用 KDF,key_str 可以是任何任意資訊,例如密碼或通行詞。在函數的其他引數中,您可以指定 KDF 名稱,然後新增其他選項以根據 KDF 的情況提高安全性。

    當您使用 KDF 時,函數會從 key_str 中傳遞的資訊,以及您在其他引數中提供的任何鹽或其他資訊建立密碼強金鑰。衍生金鑰用於加密和解密資料,並且它會保留在 MySQL 伺服器執行個體中,使用者無法存取。強烈建議使用 KDF,因為它比指定您自己的預製金鑰或在使用函數時透過更簡單的方法衍生金鑰提供更好的安全性。

    如果您不使用 KDF,對於 128 位元的金鑰長度,將金鑰傳遞至 key_str 引數的最安全方法是建立一個真正的隨機 128 位元值,並將其作為二進位值傳遞。例如

    INSERT INTO t
    VALUES (1,AES_ENCRYPT('text',UNHEX('F3229A0B371ED2D9441B830D21A390C3')));

    通行詞可用於透過雜湊通行詞來產生 AES 金鑰。例如

    INSERT INTO t
    VALUES (1,AES_ENCRYPT('text', UNHEX(SHA2('My secret passphrase',512))));

    如果您超出 128 位元的金鑰長度上限,則會傳回警告。如果您不使用 KDF,請勿直接將密碼或通行詞傳遞至 key_str,請先雜湊它。先前版本的此文件建議使用前一種方法,但現在不再建議使用,因為此處顯示的範例更安全。

    init_vector

    初始化向量,適用於需要它的區塊加密模式。block_encryption_mode 系統變數控制模式。對於相同的資料執行個體,請將相同的 init_vector 值用於使用 AES_ENCRYPT() 加密和使用 AES_DECRYPT() 解密。

    注意

    如果您使用 KDF,則必須為此引數指定初始化向量或空字串,才能存取後面的引數來定義 KDF。

    對於需要初始化向量的模式,它必須為 16 個位元組或更長(會忽略超過 16 個位元組的位元組)。如果缺少 init_vector,則會發生錯誤。對於不需要初始化向量的模式,則會忽略它,並且如果指定了 init_vector,則會產生警告,除非您使用 KDF。

    系統變數 block_encryption_mode 的預設值是 aes-128-ecb,也就是 ECB 模式,不需要初始化向量。其他允許的區塊加密模式 CBC、CFB1、CFB8、CFB128 和 OFB 都需要初始化向量。

    呼叫 RANDOM_BYTES(16) 可以產生用於初始化向量的隨機位元組字串。

    kdf_name

    金鑰衍生函式 (KDF) 的名稱,用於從傳入的 key_str 金鑰材料以及 KDF 適合的其他引數建立金鑰。選用。

    對於相同的資料實例,使用相同的 kdf_name 值來使用 AES_ENCRYPT() 加密,並使用 AES_DECRYPT() 解密。當您指定 kdf_name 時,您必須指定 init_vector,使用有效的初始化向量,或者如果加密模式不需要初始化向量,則使用空字串。

    支援下列值

    hkdf

    HKDF,可從 OpenSSL 1.1.0 取得。HKDF 從金鑰材料中提取偽隨機金鑰,然後將其擴展為其他金鑰。使用 HKDF,您可以指定一個可選的鹽 (salt) 和特定於上下文的資訊,例如應用程式詳細資訊 (info),以包含在金鑰材料中。

    pbkdf2_hmac

    PBKDF2,可從 OpenSSL 1.0.2 取得。PBKDF2 將偽隨機函式應用於金鑰材料,並重複此過程多次以產生金鑰。使用 PBKDF2,您可以指定一個可選的鹽 (salt) 以包含在金鑰材料中,並設定用於產生金鑰的迭代次數 (iterations)。

    在此範例中,HKDF 被指定為金鑰衍生函式,並提供了鹽和上下文資訊。包含了初始化向量的引數,但它是空字串

    SELECT AES_ENCRYPT('mytext','mykeystring', '', 'hkdf', 'salt', 'info');

    在此範例中,PBKDF2 被指定為金鑰衍生函式,提供了鹽,並且迭代次數從建議的最小值增加了一倍

    SELECT AES_ENCRYPT('mytext','mykeystring', '', 'pbkdf2_hmac','salt', '2000');
    salt

    要傳遞給金鑰衍生函式 (KDF) 的鹽。選用。HKDF 和 PBKDF2 都可以使用鹽,建議使用它們來幫助防止基於常見密碼字典或彩虹表的攻擊。

    鹽由隨機資料組成,為了安全起見,每次加密操作都必須不同。呼叫 RANDOM_BYTES() 可以產生用於鹽的隨機位元組字串。此範例產生一個 64 位元的鹽

    SET @salt = RANDOM_BYTES(8);

    對於相同的資料實例,使用相同的 salt 值來使用 AES_ENCRYPT() 加密,並使用 AES_DECRYPT() 解密。鹽可以安全地與加密資料一起儲存。

    info

    用於 HKDF 的特定於上下文的資訊,以包含在金鑰材料中,例如有關應用程式的資訊。選用;當您指定 hkdf 作為 KDF 名稱時可用。HKDF 會將此資訊新增到 key_str 中指定的金鑰材料和 salt 中指定的鹽,以產生金鑰。

    對於相同的資料實例,使用相同的 info 值來使用 AES_ENCRYPT() 加密,並使用 AES_DECRYPT() 解密。

    iterations

    PBKDF2 在產生金鑰時使用的迭代計數。選用;當您指定 pbkdf2_hmac 作為 KDF 名稱時可用。較高的計數可以更好地抵抗暴力攻擊,因為它對攻擊者來說具有更高的計算成本,但對於金鑰衍生過程來說,情況必然也是如此。如果您不指定此引數,則預設值為 1000,這是 OpenSSL 標準建議的最小值。

    對於相同的資料實例,使用相同的 iterations 值來使用 AES_ENCRYPT() 加密,並使用 AES_DECRYPT() 解密。

    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 CAST(AES_DECRYPT(@crypt_str,@key_str,@init_vector) AS CHAR);
    +-------------------------------------------------------------+
    | CAST(AES_DECRYPT(@crypt_str,@key_str,@init_vector) AS CHAR) |
    +-------------------------------------------------------------+
    | text                                                        |
    +-------------------------------------------------------------+
  • COMPRESS(string_to_compress)

    壓縮字串並將結果作為二進位字串傳回。此函式要求 MySQL 已使用壓縮程式庫 (例如 zlib) 編譯。否則,傳回值始終為 NULL。如果 string_to_compressNULL,則傳回值也為 NULL。可以使用 UNCOMPRESS() 解壓縮壓縮的字串。

    mysql> SELECT LENGTH(COMPRESS(REPEAT('a',1000)));
            -> 21
    mysql> SELECT LENGTH(COMPRESS(''));
            -> 0
    mysql> SELECT LENGTH(COMPRESS('a'));
            -> 13
    mysql> SELECT LENGTH(COMPRESS(REPEAT('a',16)));
            -> 15

    壓縮的字串內容以下列方式儲存

    • 空字串儲存為空字串。

    • 非空字串儲存為未壓縮字串的 4 位元組長度(低位元組優先),後跟壓縮的字串。如果字串以空格結尾,則會新增一個額外的 . 字元,以避免如果結果儲存在 CHARVARCHAR 資料行中時,出現尾隨空格修剪的問題。(但是,無論如何,不建議使用非二進位字串資料類型(例如 CHARVARCHAR)來儲存壓縮字串,因為可能會發生字元集轉換。請改用 VARBINARYBLOB 二進位字串資料行。)

    如果從 mysql 用戶端內呼叫 COMPRESS(),則二進位字串會根據 --binary-as-hex 的值使用十六進位表示法顯示。有關該選項的更多資訊,請參閱第 6.5.1 節,「mysql — MySQL 命令列用戶端」

  • MD5(str)

    計算字串的 MD5 128 位元檢查碼。該值以 32 個十六進位數字的字串形式傳回,如果引數為 NULL,則傳回 NULL。例如,傳回值可以用作雜湊金鑰。請參閱本節開頭關於有效儲存雜湊值的注意事項。

    傳回值是連線字元集中的字串。

    如果啟用了 FIPS 模式,則 MD5() 會傳回 NULL。請參閱第 8.8 節,「FIPS 支援」

    mysql> SELECT MD5('testing');
            -> 'ae2b1fca515949e5d54fb22b8ed95575'

    這是 RSA Data Security, Inc. MD5 訊息摘要演算法。

    請參閱本節開頭關於 MD5 演算法的注意事項。

  • RANDOM_BYTES(len)

    此函式會傳回使用 SSL 程式庫的亂數產生器產生的 len 個隨機位元組的二進位字串。len 的允許值範圍是 1 到 1024。對於該範圍之外的值,會發生錯誤。如果 lenNULL,則傳回 NULL

    RANDOM_BYTES() 可以用於為 AES_DECRYPT()AES_ENCRYPT() 函式提供初始化向量。在此情況下使用時,len 必須至少為 16。允許較大的值,但會忽略超過 16 個位元組的位元組。

    RANDOM_BYTES() 產生一個隨機值,這使得其結果不具確定性。因此,使用此函式的陳述式對於基於陳述式的複寫是不安全的。

    如果從 mysql 用戶端內呼叫 RANDOM_BYTES(),則二進位字串會根據 --binary-as-hex 的值使用十六進位表示法顯示。有關該選項的更多資訊,請參閱第 6.5.1 節,「mysql — MySQL 命令列用戶端」

  • SHA1(str), SHA(str)

    計算字串的 SHA-1 160 位元檢查碼,如 RFC 3174(安全雜湊演算法)中所述。該值以 40 個十六進位數字的字串形式傳回,如果引數為 NULL,則傳回 NULL。此函式的可能用途之一是用作雜湊金鑰。請參閱本節開頭關於有效儲存雜湊值的注意事項。SHA()SHA1() 同義。

    傳回值是連線字元集中的字串。

    mysql> SELECT SHA1('abc');
            -> 'a9993e364706816aba3e25717850c26c9cd0d89d'

    SHA1() 可以被認為是密碼學上更安全的 MD5() 等效函式。但是,請參閱本節開頭關於 MD5 和 SHA-1 演算法的注意事項。

  • SHA2(str, hash_length)

    計算 SHA-2 系列的雜湊函式(SHA-224、SHA-256、SHA-384 和 SHA-512)。第一個引數是要雜湊的純文字字串。第二個引數表示所需的結果位元長度,其值必須為 224、256、384、512 或 0(相當於 256)。如果任一引數為 NULL,或者雜湊長度不是允許的值之一,則傳回值為 NULL。否則,函式結果是包含所需位數的雜湊值。請參閱本節開頭關於有效儲存雜湊值的注意事項。

    傳回值是連線字元集中的字串。

    mysql> SELECT SHA2('abc', 224);
            -> '23097d223405d8228642a477bda255b32aadbce4bda0b3f7e36c9da7'

    此函式僅在 MySQL 已設定 SSL 支援時才能運作。請參閱第 8.3 節,「使用加密連線」

    SHA2() 在密碼學上可以認為比 MD5()SHA1() 更安全。

  • STATEMENT_DIGEST(statement)

    給定一個 SQL 語句作為字串,以連線字元集返回語句摘要雜湊值作為字串,如果參數為 NULL,則返回 NULL。相關的 STATEMENT_DIGEST_TEXT() 函數會返回正規化的語句摘要。關於語句摘要的資訊,請參閱第 29.10 節,「Performance Schema 語句摘要與採樣」

    這兩個函數都使用 MySQL 解析器來解析語句。如果解析失敗,則會發生錯誤。只有在語句以文字字串形式提供時,錯誤訊息才會包含解析錯誤。

    max_digest_length 系統變數決定這些函數用於計算正規化語句摘要的最大位元組數。

    mysql> SET @stmt = 'SELECT * FROM mytable WHERE cola = 10 AND colb = 20';
    mysql> SELECT STATEMENT_DIGEST(@stmt);
    +------------------------------------------------------------------+
    | STATEMENT_DIGEST(@stmt)                                          |
    +------------------------------------------------------------------+
    | 3bb95eeade896657c4526e74ff2a2862039d0a0fe8a9e7155b5fe492cbd78387 |
    +------------------------------------------------------------------+
    mysql> SELECT STATEMENT_DIGEST_TEXT(@stmt);
    +----------------------------------------------------------+
    | STATEMENT_DIGEST_TEXT(@stmt)                             |
    +----------------------------------------------------------+
    | SELECT * FROM `mytable` WHERE `cola` = ? AND `colb` = ?  |
    +----------------------------------------------------------+
  • STATEMENT_DIGEST_TEXT(statement)

    給定一個 SQL 語句作為字串,以連線字元集返回正規化的語句摘要作為字串,如果參數為 NULL,則返回 NULL。有關其他討論和範例,請參閱相關的 STATEMENT_DIGEST() 函數的說明。

  • UNCOMPRESS(string_to_uncompress)

    解壓縮由 COMPRESS() 函數壓縮的字串。如果參數不是壓縮的值,則結果為 NULL;如果 string_to_uncompressNULL,則結果也為 NULL。此函數要求 MySQL 已使用壓縮函式庫(例如 zlib)進行編譯。否則,傳回值始終為 NULL

    mysql> SELECT UNCOMPRESS(COMPRESS('any string'));
            -> 'any string'
    mysql> SELECT UNCOMPRESS('any string');
            -> NULL
  • UNCOMPRESSED_LENGTH(compressed_string)

    傳回壓縮字串在壓縮前的長度。如果 compressed_stringNULL,則傳回 NULL

    mysql> SELECT UNCOMPRESSED_LENGTH(COMPRESS(REPEAT('a',30)));
            -> 30
  • VALIDATE_PASSWORD_STRENGTH(str)

    給定一個代表明文密碼的參數,此函數會傳回一個整數,以指示密碼的強度,如果參數為 NULL,則傳回 NULL。傳回值範圍從 0(弱)到 100(強)。

    VALIDATE_PASSWORD_STRENGTH() 的密碼評估由 validate_password 元件完成。如果未安裝該元件,則函數始終傳回 0。有關安裝 validate_password 的資訊,請參閱第 8.4.3 節,「密碼驗證元件」。要檢查或配置影響密碼測試的參數,請檢查或設定由 validate_password 實作的系統變數。請參閱第 8.4.3.2 節,「密碼驗證選項和變數」

    密碼會受到越來越嚴格的測試,並且傳回值會反映滿足了哪些測試,如下表所示。此外,如果啟用 validate_password.check_user_name 系統變數,且密碼與使用者名稱相符,則無論其他 validate_password 系統變數如何設定,VALIDATE_PASSWORD_STRENGTH() 都會傳回 0。

    密碼測試 傳回值
    長度 < 4 0
    長度 ≥ 4 且 < validate_password.length 25
    符合原則 1 (LOW) 50
    符合原則 2 (MEDIUM) 75
    符合原則 3 (STRONG) 100