Database-Design

儲存加密 API 標識符的最佳方式 (MariaDB)

  • November 29, 2021

因此,為了獲得最大的安全性,我必須在使用應用程序時定期加密一些我需要呼叫 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,但沒有說為什麼,所以我更喜歡堅持它..

引用自:https://dba.stackexchange.com/questions/303213