Harden the security where hash values are compared

Created on 30 December 2014, over 10 years ago
Updated 4 May 2025, 6 days ago

Problem/Motivation

Currently the equality operator is used throughout Drupal core when hash values are compared. As pointed out elsewhere this can result in false positives under certain circumstances. This can be the case when a hashing operation results in values which are interpreted as a number by PHP (type juggling).

The following grep turns up all relevant hash/token comparisons in the code base excluding vendor directory and clear false positives (for example from the text token replacement system, aka token module):

$ find . -type f -and -not -name '*.js' -and -not -name '*.tokens.inc' -and -not -name 'token.api.php' -and -not -name PoHeader.php -and -not -path '*/vendor/*' | xargs git grep '[^=!]==[^=]' | grep -E 'token|hash' | cat -n
     1	core/lib/Drupal/Core/Password/PhpassHashedPassword.php:    return ($hash && $stored_hash == $hash);
     2	core/modules/toolbar/src/Controller/ToolbarController.php:    return AccessResult::allowedIf($this->currentUser()->hasPermission('access toolbar') && $hash == _toolbar_get_subtrees_hash($langcode))->cachePerPermissions();
     3	core/modules/user/src/AccountForm.php:        $user_pass_reset = $pass_reset = isset($_SESSION['pass_reset_' . $account->id()]) && (\Drupal::request()->query->get('pass-reset-token') == $_SESSION['pass_reset_' . $account->id()]);
     4	core/modules/user/src/Controller/UserController.php:      if ($timestamp <= $current && $current - $timestamp < $timeout && $user->id() && $timestamp >= $user->getLastLoginTime() && $hashed_pass == user_pass_rehash($user->getPassword(), $timestamp, $user->getLastLoginTime(), $user->id())) {

Proposed resolution

  • Introduce a new static method \Drupal\Component\Utility\Crypt::hashEquals() wrapping around the constant time hash_equals() function.
  • Replace all relevant hash/token comparisons with the new Crypt::hashEquals() method.

Remaining tasks

  • Review

User interface changes

None.

API changes

API addition (Crypt::hashEquals()).

Beta phase evaluation

<!--Uncomment the relevant rows for the issue. -->

Original report

As of PHP 5.6, the function hash_equals() was added to help prevent timing attack security issues.

All this does is provide a string comparison for the use inside of php.

I have made a patch that adds forward compatibility by checking the php version constants.

see: http://us3.php.net/manual/en/function.hash-equals.php
see: http://us3.php.net/manual/en/migration56.new-features.php

<?php
  // use more secure hash_equal() that was introduced in php 5.6 and greater.
  // see: http://php.net/manual/en/function.hash-equals.php.
  if (PHP_MAJOR_VERSION > 4 && PHP_MINOR_VERSION > 5) {
    return ($hash && hash_equals($stored_hash, $hash));
  }
?>

I am checking the php constants instead of using a function_exists() to prevent the possibility of some attacker implementing their own hash_equals() function for php versions < 5.6.

πŸ› Bug report
Status

Fixed

Version

8.0 ⚰️

Component

user system

Created by

πŸ‡ΊπŸ‡ΈUnited States thekevinday

Live updates comments and jobs are added and updated live.
  • PHP 5.6

    The issue particularly affects sites running on PHP version 5.6.0 or later.

  • Needs backport to D7

    After being applied to the 8.x branch, it should be considered for backport to the 7.x branch. Note: This tag should generally remain even after the backport has been written, approved, and committed.

  • Security improvements

    It makes Drupal less vulnerable to abuse or misuse. Note, this is the preferred tag, though the Security tag has a large body of issues tagged to it. Do NOT publicly disclose security vulnerabilities; contact the security team instead. Anyone (whether security team or not) can apply this tag to security improvements that do not directly present a vulnerability e.g. hardening an API to add filtering to reduce a common mistake in contributed modules.

Sign in to follow issues

Comments & Activities

Not all content is available!

It's likely this issue predates Contrib.social: some issue and comment data are missing.

Production build 0.71.5 2024