2013-02-05 53 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