在一組 MD5 和上使用按位異或是個好主意嗎?
我在 Oracle 中設計了一個 SQL 聚合函式,它對儲存在列中的值的所有 MD5 和進行按位異或。
例如,如果我的表是:
+-----+----------+---------+ | Key | Sequence | Value | +-----+----------+---------+ | 1 | 1 | 'Hello' | | 1 | 2 | 'World' | | 2 | 1 | '1234' | | 3 | 0 | (empty) | | 4 | 1 | 'Hello' | | 4 | 3 | 'World' | +-----+----------+---------+
我可以在 Oracle 中執行以下查詢:
with t AS (select 1 key, 1 sequence, 'Hello' value FROM dual union all select 1, 2, 'World' from dual union all select 2, 1, '1234' from dual union all select 3, 0, '' from dual /* ... */ ) select key, md5_agg(value) from t group by key
並獲取(不幸的是,Oracle 中的聚合函式忽略 NULL 值並被
''
視為 NULL)+---+----------------------------------+ |key| md5_agg(value) | +---+----------------------------------+ | 1 | 7EBD0B1DA67F965F802D31DF25C4B321 | | 2 | 81DC9BDB52D04DC20036DBD8313ED055 | | 3 | 00000000000000000000000000000000 | | 4 | 7EBD0B1DA67F965F802D31DF25C4B321 | +---+----------------------------------+
**當我比較同一個表的子集時,我想使用這種方法來比較某些列的內容是否相等(想想在跨越同一個表中的多行的複雜結構中查找重複項)。**有了這個結果,我知道我對鍵 1 和 4 有相同的子集。
這種方法的局限性是什麼?以下是我可以列出的:
- 僅當我的列包含不同的值時,這才有趣。如果我的列包含兩次相同的字元串,則該
xor
操作將是空操作。- 由於 Oracle 的限制,如果我的列包含空值,則它們不計算在內。
考慮到這些限制,是否仍然可以從
md5_agg
由不同的非空值計算出的兩個相等結果中推斷出原始值構成相同的集合?為了重新制定,MD5 和不同字元串的 XOR 總和是否有可能為 0?
這裡有兩點需要考慮:
兩個不同的字元串給出相同的 MD5 雜湊的可能性有多大?
這被稱為雜湊衝突。一個好的散列函式使這個機率盡可能小(這大約是 $ 1/2^{128} $ 對於 MD5)。如果你有大量的字元串要散列,它們之間的任何衝突的可能性都會增加……但你需要大約 $ 2^{64} $ 字元串具有不可忽略的碰撞機會(這是生日悖論)。
不幸的是,MD5 不是一個好的散列函式——它的抗碰撞性基本上被破壞了。創建兩個具有相同雜湊的不同字元串並不需要太多工作。因此,如果即使面對攻擊者將字元串輸入數據庫時也想確保這一點,請不要使用 MD5。請改用其中一種 SHA-2 雜湊函式,它們仍然被認為是安全的。 (它們還具有更大的輸出大小,這也使生日界限更高。)
假設一個理想的散列函式(例如隨機預言機),我們可以將問題簡化為:
給定兩組 $ A $ , $ B $ 的 $ k_A $ , $ k_B $ 相同長度的隨機位串 $ n $ ,我們有這個的可能性有多大?
$$ \bigoplus_{i=1}^{k_A} A_i = \bigoplus_{j=1}^{k_B} B_j $$ 實際上,隨機字元串(甚至許多非隨機字元串與隨機字元串)的 XOR 又是一個隨機字元串,所以這歸結為兩個隨機字元串大小的可能性有多大 $ n $ 相同嗎?
這裡我們得到和上面一樣的答案:這個機率是 $ 1/2^{n} $ 對於兩個字元串,然後大約 $ 2^{n/2} $ 這樣的隨機字元串您將很有可能發生碰撞。
所以,看起來你的方案是可靠的,只要確保選擇一個輸出大小足夠大的好的散列函式(不是 MD5,甚至 SHA-1 現在的名聲都不好) $ n $ 因此散列的單個字元串的數量與 $ 2^{n/2} $ .但是如果對手可以控制你的子集的足夠大的一部分(包括一組周圍的子集) $ n $ 這樣的字元串就足夠了,如果他可以任意注入這些字元串,則需要的更少,但需要更多的預先計算來選擇它們),他可以選擇這些字元串,使得它們的 XOR 會給出他想要的任何值,這然後轉化為最終“雜湊”中的任意碰撞。請改用 fgrieu 答案中突出顯示的方法。