用于检查散列相等性的PHP中strcmp vs.==vs.===的值

用于检查散列相等性的PHP中strcmp vs.==vs.===的值,php,string,security,bcrypt,crypt,Php,String,Security,Bcrypt,Crypt,我使用crypt()在PHP中散列密码,并试图找出在执行密码检查时测试结果散列相等性的最安全方法 我可以看到三个选项: 选项1-双倍等于 function checkPassword($hash, $password) { return crypt($password, $hash) == $hash; } function checkPassword($hash, $password) { return crypt($password, $hash) === $hash; }

我使用
crypt()
在PHP中散列密码,并试图找出在执行密码检查时测试结果散列相等性的最安全方法

我可以看到三个选项:

选项1-双倍等于

function checkPassword($hash, $password)
{
    return crypt($password, $hash) == $hash;
}
function checkPassword($hash, $password)
{
    return crypt($password, $hash) === $hash;
}
选项2-三重等于

function checkPassword($hash, $password)
{
    return crypt($password, $hash) == $hash;
}
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==“1”
=True

1==“1”
=False


因为我们不太关心类型,所以我会保持简单,并使用
=

当涉及到安全性时,我更喜欢使用
==
操作符
=
确保两个操作数完全相同,而无需为了“帮助”比较实现成功匹配而尝试进行一些转换,因为这可能有助于开发松散类型的语言,如PHP

当然,其中一个操作数是可信的。数据库中的哈希值是可信任的,而用户输入是不可信任的

人们总是会犹豫一段时间,得出结论,在特定情况下使用
=
没有风险。大概但例如

  "0afd9f7b678fdefca" == 0 is true
  "aafd9f7b678fdefca" == 0 is also true
当PHP试图将“散列”转换为一个数字(可能使用atoi)时,该数字给出0。虽然
crypt
不太可能返回0,但我更愿意使用
===
最大限度地减少密码不匹配的情况(并接听支持电话),而不是允许使用
=
出现我没有想到的罕见情况

对于strcmp,如果不同,函数返回
0
,如果相等,函数返回0。但是

  strcmp("3", 0003) returns 0
  strcmp("0003", 0003) returns -3
这并不奇怪。文本
0003
实际上是一个整数,
3
,由于strcmp需要一个字符串,
3
将转换为
“3”
。但这表明在这种情况下可能会发生一些转换,因为strcmp是一个函数,而
==
是语言的一部分


因此,在这种情况下,我的首选是
==
(无论如何,它比
=
快)。

这是不正确的,请查看函数的定义。 根据PHP的说法:

如果str1小于str2,则返回<0

>0如果str1大于str2,

和0(如果它们相等)

如果str1小于str2,则返回小于0。注意短语“小于”,它不仅返回-1,还返回任何负值。当str1大于str2时也会发生同样的情况,但它返回一个非零值的正值。它返回一个正值,可以是1,也可以是其后的任何数字

strcmp()
返回一个数字,该数字是以发现相似的最后一个字符开头的两个字符串之间的差值

以下是一个例子:

$output=strcmp(“红色”、“蓝色”)


变量$output with包含值16

您应该使用内置于PHP中的hash_equals()函数。没有必要让你自己发挥作用。hash_equals()将返回一个布尔值


在我看来,使用==或===来比较字符串通常不是一个好主意,更不用说散列字符串了。

我知道
==
==
之间的区别,但我正试图找出是否有我遗漏的特定安全敏感案例。例如,有没有理由不使用strcmp
?因为您不关心二进制安全比较,所以我不会使用strcmp。您不关心字符串的不同程度,只关心它们在语义上是否相同。如果
bcrypt
由于某种原因失败了怎么办?非字符串返回值是否可能被视为等于
$hash
的字符串值,其中该变量是有效的hash?简言之,否。它不应该有任何不同。@IanP不,这不是问题,他需要一个安全比较两个字符串的函数,我们不应该关心字符串“应该”或“可能”是什么看样子,因为这些东西都可以改变阅读它:@Userpassword有趣的bug!我想知道PHP在转换为数字时如何处理字符串,如
$2a$10$…$
。如果您只想可靠地比较哈希,只需使用
==
。如果你真的关心安全性和潜在的定时攻击(即使网络抖动),你应该看一看或讨论,或者使用
hash_equals()
函数(PHP5.6+)。检查这是我见过的最合理的答案。我同意类型和值对于避免“cast helper”出现问题都很重要。请注意,在测试像
password\u hash
这样的强函数生成的哈希值时,这是
password\u hash
生成的值的正确答案,但是主流PHP在询问时不存在
hash_equals
,并且它不适用于平面散列(它无论如何都不应该使用,但有时是遗留的)