儲存加密 API 標識符的最佳方式 (MariaDB)
因此,為了獲得最大的安全性,我必須在使用應用程序時定期加密一些我需要呼叫 API 的特定操作的字元串密鑰,因此還應該考慮性能。
要加密的數據是 35 - 40 個字元的字元串。
我使用的 RDBMS 是 MariaDB。
為了正確地做到這一點,我一直在檢查文件,並且我正在使用
AES_ENCRYPT()
它來加密和儲存數據。據我了解,這是附帶的:
- 需要一個固定長度的密鑰,比如 128 位。因此,我將如何儲存數據的一個範例是:
INSERT INTO sample VALUES( AES_ENCRYPT( "secret_identifier", SHA2( "my_encryption_key", 512))
- 保存數據的列的數據類型是
VARBINARY
,為了避免任何有關填充/剝離任何字元等的問題。至少我的結論是這是最好的類型,因為我需要重新使用數據的解密原始版本用於正常 API 呼叫。- 列欄位的大小就是根據這個計算出來的,所以:
16 x (trunc(string_length / 16) + 1)
- 知道我們有最大 40 個字元的長度,為了安全起見,算上 80 個字元,結果長度為:
16 x (5 + 1) = 96
所以我會使用一
VARBINARY(100)
列來儲存數據。
- 要檢索原始未加密數據,我將使用:
SELECT AES_DECRYPT( column_name, SHA2( "my_encryption_key", 512))
這些考慮是否正確?我必須保證,因為將儲存數千/數百萬個 API 標識符。我什至不想考慮需要重新生成所有 API 標識符的噩夢(對於這一代,人類需要這樣做!)因為應用的加密以某種方式破壞了數據。
SHA2( "my_encryption_key", 512)
並不比安全,my_encryption_key
但需要更長的時間。加密已經加密的東西(即使是手動加密)會混淆,但不會增加安全性。在一些罕見的情況下,它會消除混淆。
桌面上留下的主要安全問題:字元串“my_encryption_key”儲存在哪裡?它似乎在您的 PHP 程式碼中以純文字形式存在。但這有多安全?
我見過的一個技巧是在 Apache 中使用一個 mod 從“root 400”文件載入密鑰,然後將其提供給您的 PHP 程序。這意味著密鑰在兩個地方——一個在系統和記憶體中與“root”一樣安全的文件(供 Apache 交給 PHP)。兩者都比 PHP 程式碼中的純文字安全得多*。*
並且系統需要讓黑客相對不可能注入他們自己的 PHP 程式碼並執行它。
我創建了一個小提琴,它創建了兩個表,一個使用
VARBINARY(100)
列儲存加密數據,另一個將其儲存在BLOB
列中。在後一種情況下,您然後通過將結果轉換為 CHAR 來檢索解密的數據(用於測試它的作用)。我還使用隨機生成的 32 字節長密鑰進行加密,另一個使用 128 位長雜湊的加密,用於兩個表,以檢查密鑰長度 + using 的影響
AES
。你可以在這裡找到小提琴。
非常有趣的是,我們可以看到在密鑰大小方面完全沒有區別,至少看起來是這樣。原始數據和使用隨機長度密鑰 + 原始數據的加密 + 解密和使用 128 位長密鑰的加密 + 解密之間的比較都返回匹配。
但是,當我沒有指定表
CHAR
中列的字元限制sample_blob
時,在小提琴中執行架構時會出現錯誤,說解密的數據被截斷。然後,當我指定CHAR(50)
而不是表CHAR
的相關列的數據類型時sample_blob
,一切順利。由此,我得出結論(這是一個猜測!)我的 API 標識符有問題的主要問題是我實際上使用了 table 中的方法
sample_blob
;因此使用BLOB
數據類型來儲存加密數據,這需要您在檢索解密數據時進行某種轉換,以便能夠將其讀取為字元串。然後,當我使用以下方法檢索數據時,我很可能截斷了解密的數據:
SELECT CAST ( AES_DECRYPT( encrypted_string, "key" ) AS CHAR )
解密時導致標識符不相等。我由此得出的結論是,最好的方法是遵循我的問題中描述的方法,使用
VARBINARY(100)
列來儲存加密數據,其中 100 字節的長度如上所述計算。然後當您插入數據時,我在文件中發現您的加密數據實際上可能會被儲存而不會引發錯誤,儘管您插入的數據實際上已被截斷!在這種情況下,如果您在嚴格模式下執行查詢,MySQL 只會拋出警告,並且只會因錯誤而中斷,如此處所述。從理論上講,您的 API 提供者可以更改 API 密鑰的結構,使其更長或其他任何內容,這可能導致您的列長度限制(在本例中
VARBINARY(100)
為 )不再足夠長,從而截斷數據。您甚至不會在不檢查警告的情況下注意到這一點,而您的解密也可以在沒有錯誤的情況下進行,但它會返回解密後的截斷數據,因此 API 標識符損壞,儘管系統從未真正報告過錯誤!為了儲存加密數據,我將驗證插入時沒有引發 SQL 警告。要檢索數據,您只需使用:
SELECT AES_DECRYPT( encrypted_string, SHA2("key",512) )
因此不使用轉換/轉換,因此您不應該遇到數據截斷問題。我還使用了密鑰的雜湊值,以確保使用的密鑰長度為 128 位,即使這似乎不會影響我上面的範例;再次最小化任何填充/截斷問題的機會,這次與使用的加密密鑰有關。MYSQL 和 MariaDB Docs 都說在使用 時需要一個固定的密鑰長度
AES
,但沒有說為什麼,所以我更喜歡堅持它..