2013-02-05 54 views
15

我使用crypt()在PHP中對哈希密碼進行哈希,並且試圖找出在執行密碼檢查時測試結果哈希的相等性的最安全方法。strcmp與==對比在PHP == == ===檢查哈希值是否相等

有三種選擇,我可以看到:

選項1 - 雙等於

function checkPassword($hash, $password) 
{ 
    return crypt($password, $hash) == $hash; 
} 

選項2 - 三人的Equals

function checkPassword($hash, $password) 
{ 
    return crypt($password, $hash) === $hash; 
} 

選項3 - strcmp()

function checkPassword($hash, $password) 
{ 
    return strcmp(crypt($password, $hash), $hash) === 0; 
} 

我的直覺告訴我,由於缺少類型檢查,選項1是一個壞主意,選項2或3可能會更好。但是,如果有一個特定情況下===strcmp會失敗,我無法解決。哪一個最安全?

+1

閱讀它:http://raz0r.name/vulnerabilities/simple-machines-forum/ – user956584

+0

@Userpassword有趣的bug!我想知道PHP在處理數字時如何處理'$ 2a $ 10 $ ... $'這樣的字符串...... – Polynomial

+0

如果您只想可靠地比較哈希,只需使用'==='。如果你真的關心安全性和潛在的定時攻擊(即使網絡抖動),你應該看看[this](https://github.com/delight-im/Faceless/issues/4)或[this] (https://github.com/delight-im/Faceless/pull/5)討論或使用'hash_equals()'函數(PHP 5.6+)。 – caw

回答

19

說到安全性,我更願意使用===運算符。 ===確保兩個操作數完全相同,而不是爲了「幫助」比較以達到成功的匹配而不嘗試容納某些投射 - 因爲它可能有助於開發感謝鬆散類型的語言,如PHP。

當然,其中一個操作數是可信的。來自數據庫的散列是可信的,而用戶輸入則不可信。

人們總是可以抖一會兒,得出結論在特定情況下使用==沒有風險。也許。但例如

"0afd9f7b678fdefca" == 0 is true 
    "aafd9f7b678fdefca" == 0 is also true 

爲PHP嘗試將「哈希」轉換成一個數字(可能使用的atoi),這也是0。雖然這是不可能crypt返回0,我更願意最大限度的情況下,通過使用===,密碼不匹配(並且回答支持呼叫),這比允許使用==時沒有考慮到的罕見情況要嚴重。

至於strcmp,函數返回<0>0(如果不同),如果相等則返回0。但是

strcmp("3", 0003) returns 0 
    strcmp("0003", 0003) returns -3 

畢竟這並不奇怪。字面0003實際上是一個整數,3並且因爲strcmp需要一個字符串,所以3將被轉換爲"3"。但是這表明在這種情況下可能會發生一些轉換,因爲strcmp是一個函數,而===是該語言的一部分。

所以我在這種情況下的首選爲===(反正比==快)。

+0

這是最明智的答案我'已經看到。我同意這兩種類型和價值對於避免「投資幫手」的問題都很重要。 – Polynomial

+0

請注意,在測試使用像'password_hash'這樣的強大函數生成的哈希值時,應該使用[hash_equals()](http://stackoverflow.com/a/27066499/978756)。 – Polynomial

-3

我認爲在你的情況下使用==就足夠了。

==不論類型如何檢查是否相等,而===檢查是否相等以及類型。

1 == "1" =真

1 === "1" =假

由於我們沒有太在意類型,我會保持它的簡單,並與==去。

+1

我知道'=='和'==='之間的區別,但我'如果有一個特定的安全敏感的案例,我不知道該如何解決。例如,是否有一個原因*不*使用'strcmp'? – Polynomial

+0

既然你不關心二進制安全比較,我不會使用strcmp。你並不關心字符串有多不同 - 你只關心它們是否在語義上相同。 –

+0

如果'bcrypt'由於某種原因失敗會怎麼樣?可能有可能將非字符串返回值視爲等於'$ hash'的字符串值,其中該變量是有效的哈希值? – Polynomial

0

這是不正確的,請看功能的定義。 據PHP:

Returns < 0 if str1 is less than str2;

> 0 if str1 is greater than str2,

and 0 if they are equal

如果str1小於str2的它返回小於0。請注意短語「小於」,它不會返回-1,而是任何負值。當str1大於str2時會發生同樣的情況,但它會返回一個正值,非零值。它返回一個正值,可以是1,或者其後的任何數字。

strcmp()返回一個數字,它是兩個字符串之間的差異,從最後一個被認爲是相似的字符開始。

下面是一個例子:

$output = strcmp("red", "blue");

變量$輸出,包含16

6

值,您應該使用hash_equals()函數內置到PHP。沒有必要製作你自己的功能。 hash_equals()將返回一個布爾值。

在我看來,使用==或===來比較字符串通常不是一個好主意,更不用說散列字符串了。

+1

現在這是'password_hash'生成的值的正確答案,但在詢問時主流PHP中不存在'hash_equals',並且它不適用於平面哈希(它不應該用於任何有時需要遺留) – Polynomial