文字

hash_equals

(PHP 5 >= 5.6.0)

hash_equals可防止时序攻击的字符串比较

说明

bool hash_equals ( string $known_string , string $user_string )

比较两个字符串,无论它们是否相等,本函数的时间消耗是恒定的。

本函数可以用在需要防止时序攻击的字符串比较场景中, 例如,可以用在比较 crypt() 密码哈希值的场景。

参数

known_string

已知长度的、要参与比较的 string

user_string

用户提供的字符串

返回值

当两个字符串相等时返回 TRUE ,否则返回 FALSE

错误/异常

如果所提供的 2 个参数中任何一个不是字符串, 会导致 E_WARNING 消息。

范例

Example #1 例程

<?php
$expected  
crypt ( '12345' '$2a$07$usesomesillystringforsalt$' );
$correct    crypt ( '12345' '$2a$07$usesomesillystringforsalt$' );
$incorrect  crypt ( 'apple' ,   '$2a$07$usesomesillystringforsalt$' );

var_dump ( hash_equals ( $expected $correct ));
var_dump ( hash_equals ( $expected $incorrect ));
?>

以上例程会输出:

bool(true)
bool(false)

注释

Note:

要想成功进行比较,那么所提供的 2 个参数必须是相同长度的字符串。 如果所提供的字符串长度不同,那么本函数会立即返回 FALSE , 在时序攻击的场景下,已知字符串的长度可能会被泄露。

Note:

非常重要的一点是,用户提供的字符串必须是第二个参数。

用户评论:

[#1] David Grudl [2015-11-25 17:55:56]

Very short timing attack safe string comparison for PHP < 5.6

<?php
function hash_equals($a$b) {
    return 
substr_count($a $b"\0") * === strlen($a $b);
}
?>

[#2] Cedric Van Bockhaven [2015-04-15 09:01:34]

Our server does not support the hash_equals function. We are using the following snippet which also has support for strings of different length:

<?php
if(!function_exists('hash_equals')) {
    function 
hash_equals($a$b) {
        
$ret strlen($a) ^ strlen($b);
        
$ret |= array_sum(unpack("C*"$a^$b));
        return !
$ret;
    }
}
?>

[#3] Markus P. N. [2014-09-04 21:46:24]

I don't know why asphp at dsgml dot com got that many downvotes, the function seems to work.

I extended it a bit to support strings of diffent length and to handle errors and ran some tests:

The test results and how to reproduce them: http://pastebin.com/mLMXJeva

The function:
<?php

if (!function_exists('hash_equals')) {

    

    
function hash_equals($known_string$user_string)
    {
        if (
func_num_args() !== 2) {
            
// handle wrong parameter count as the native implentation
            
trigger_error('hash_equals() expects exactly 2 parameters, ' func_num_args() . ' given'E_USER_WARNING);
            return 
null;
        }
        if (
is_string($known_string) !== true) {
            
trigger_error('hash_equals(): Expected known_string to be a string, ' gettype($known_string) . ' given'E_USER_WARNING);
            return 
false;
        }
        
$known_string_len strlen($known_string);
        
$user_string_type_error 'hash_equals(): Expected user_string to be a string, ' gettype($user_string) . ' given'// prepare wrong type error message now to reduce the impact of string concatenation and the gettype call
        
if (is_string($user_string) !== true) {
            
trigger_error($user_string_type_errorE_USER_WARNING);
            
// prevention of timing attacks might be still possible if we handle $user_string as a string of diffent length (the trigger_error() call increases the execution time a bit)
            
$user_string_len strlen($user_string);
            
$user_string_len $known_string_len 1;
        } else {
            
$user_string_len $known_string_len 1;
            
$user_string_len strlen($user_string);
        }
        if (
$known_string_len !== $user_string_len) {
            
$res $known_string $known_string// use $known_string instead of $user_string to handle strings of diffrent length.
            
$ret 1// set $ret to 1 to make sure false is returned
        
} else {
            
$res $known_string $user_string;
            
$ret 0;
        }
        for (
$i strlen($res) - 1$i >= 0$i--) {
            
$ret |= ord($res[$i]);
        }
        return 
$ret === 0;
    }

}

?>

[#4] asphp at dsgml dot com [2014-08-28 19:48:47]

To transparently support this function on older versions of PHP use this:

<?php
if(!function_exists('hash_equals')) {
  function 
hash_equals($str1$str2) {
    if(
strlen($str1) != strlen($str2)) {
      return 
false;
    } else {
      
$res $str1 $str2;
      
$ret 0;
      for(
$i strlen($res) - 1$i >= 0$i--) $ret |= ord($res[$i]);
      return !
$ret;
    }
  }
}
?>

上一篇: 下一篇: