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


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

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 Server 執行個體中,使用者無法存取。強烈建議使用 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) 衍生金鑰基礎的輸入金鑰資料。對於同一資料執行個體,請對使用 AES_ENCRYPT() 加密和使用 AES_DECRYPT() 解密使用相同的 key_str 值。

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

    當您使用 KDF 時,該函式會從 key_str 中傳遞的資訊以及您在其他引數中提供的任何鹽或其他資訊建立密碼編譯強度高的密碼金鑰。衍生的金鑰用於加密和解密資料,並保留在 MySQL Server 執行個體中,使用者無法存取。強烈建議使用 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 系統變數控制模式。對於同一資料執行個體,請對使用 AES_ENCRYPT() 加密和使用 AES_DECRYPT() 解密使用相同的 init_vector 值。

    注意

    如果您使用的是 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 適當的其他引數。可選。

    對於同一資料執行個體,請對使用 AES_ENCRYPT() 加密和使用 AES_DECRYPT() 解密使用相同的 kdf_name 值。當您指定 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);

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

    info

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

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

    iterations

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

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

    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 節,「效能結構描述語句摘要與取樣」

    兩個函數都使用 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