表 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() |
判斷密碼強度 |
許多加密與壓縮函數會傳回可能包含任意位元組值的字串。如果您想要儲存這些結果,請使用具有 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 的值取決於十六進位字串的長度。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 | +-------------------------------------------------------------+-
壓縮字串並將結果作為二進位字串傳回。此函式要求 MySQL 已使用壓縮程式庫 (例如
zlib) 編譯。否則,傳回值始終為NULL。如果string_to_compress為NULL,則傳回值也為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壓縮的字串內容以下列方式儲存
如果從 mysql 用戶端內呼叫
COMPRESS(),則二進位字串會根據--binary-as-hex的值使用十六進位表示法顯示。有關該選項的更多資訊,請參閱第 6.5.1 節,「mysql — MySQL 命令列用戶端」。計算字串的 MD5 128 位元檢查碼。該值以 32 個十六進位數字的字串形式傳回,如果引數為
NULL,則傳回NULL。例如,傳回值可以用作雜湊金鑰。請參閱本節開頭關於有效儲存雜湊值的注意事項。傳回值是連線字元集中的字串。
如果啟用了 FIPS 模式,則
MD5()會傳回NULL。請參閱第 8.8 節,「FIPS 支援」。mysql> SELECT MD5('testing'); -> 'ae2b1fca515949e5d54fb22b8ed95575'這是 「RSA Data Security, Inc. MD5 訊息摘要演算法。」
請參閱本節開頭關於 MD5 演算法的注意事項。
此函式會傳回使用 SSL 程式庫的亂數產生器產生的
len個隨機位元組的二進位字串。len的允許值範圍是 1 到 1024。對於該範圍之外的值,會發生錯誤。如果len為NULL,則傳回NULL。RANDOM_BYTES()可以用於為AES_DECRYPT()和AES_ENCRYPT()函式提供初始化向量。在此情況下使用時,len必須至少為 16。允許較大的值,但會忽略超過 16 個位元組的位元組。RANDOM_BYTES()產生一個隨機值,這使得其結果不具確定性。因此,使用此函式的陳述式對於基於陳述式的複寫是不安全的。如果從 mysql 用戶端內呼叫
RANDOM_BYTES(),則二進位字串會根據--binary-as-hex的值使用十六進位表示法顯示。有關該選項的更多資訊,請參閱第 6.5.1 節,「mysql — MySQL 命令列用戶端」。計算字串的 SHA-1 160 位元檢查碼,如 RFC 3174(安全雜湊演算法)中所述。該值以 40 個十六進位數字的字串形式傳回,如果引數為
NULL,則傳回NULL。此函式的可能用途之一是用作雜湊金鑰。請參閱本節開頭關於有效儲存雜湊值的注意事項。SHA()與SHA1()同義。傳回值是連線字元集中的字串。
mysql> SELECT SHA1('abc'); -> 'a9993e364706816aba3e25717850c26c9cd0d89d'SHA1()可以被認為是密碼學上更安全的MD5()等效函式。但是,請參閱本節開頭關於 MD5 和 SHA-1 演算法的注意事項。計算 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 節,「使用加密連線」。
給定一個 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_uncompress為NULL,則結果也為NULL。此函數要求 MySQL 已使用壓縮函式庫(例如zlib)進行編譯。否則,傳回值始終為NULL。mysql> SELECT UNCOMPRESS(COMPRESS('any string')); -> 'any string' mysql> SELECT UNCOMPRESS('any string'); -> NULLUNCOMPRESSED_LENGTH(compressed_string)傳回壓縮字串在壓縮前的長度。如果
compressed_string為NULL,則傳回NULL。mysql> SELECT UNCOMPRESSED_LENGTH(COMPRESS(REPEAT('a',30))); -> 30VALIDATE_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.length25 符合原則 1 ( LOW)50 符合原則 2 ( MEDIUM)75 符合原則 3 ( STRONG)100