Как мигрировать хеш пароля

Дата обновления перевода 2021-09-29

Как мигрировать хеш пароля

Для того, чтобы защищать пароли, рекомендуется хранить их, используя последние алгоритмы хеширования. Это означает, что если в вашей системе поддерживается лучший алгоритм хеширования, пароль польозвателя должен быть хеширован повторно, используя более новый алгоритм, и сохранен. Это возможно с опцией migrate_from:

  1. Сконфигурируйте новый хешировщик, используя "migrate_from"
  2. Обновите пароль
  3. По желанию, Запустите миграцию паролей из пользовательского хешировщика

Сконфигурируйте новый хешировщик, используя "migrate_from"

Когда становится доступным лучший алгоритм хеширования, вы должны оставить существующий(е) хешировщик(и), переименовать его, а затем определить новый. Установите опцию migrate_from в новом хещировщике, чтобы указать на старый, наследуемый(е) хешироващик(и):

  • YAML
  • XML
  • PHP
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# config/packages/security.yaml
security:
    # ...

    password_hashers:
        # хешировщик, используемый в прошлом для некоторых пользователей
        legacy:
            algorithm: sha256
            encode_as_base64: false
            iterations: 1

        App\Entity\User:
            # новый хешироващик, вместе с его опциями
            algorithm: sodium
            migrate_from:
                - bcrypt # использует хешировщик "bcrypt" с опциями по умолчанию
                - legacy # использует хешировщик "legacy", сконфигурированный выше

С этой настройкой:

  • Новые пользователи будут хешироваться с новым алгоритмом;
  • Каждый раз при входе в систему пользователя, чей пароль все еще хранится с использованием старого алгоритма, Symfony будет верифицировать пароль со старым алгоритмом, а затем повторно хешировать и обновлять пароль, используя новый алгоритм.

Tip

Хешировщики auto, native, bcrypt и argon автоматически включают миграцию паролей, используя следующий список алгоритмов migrate_from:

  1. PBKDF2 (который использует hash_pbkdf2);
  2. Хеш (который использует hash)

Оба используют настройку hash_algorithm в качестве алгоритма. Рекомендуется использовать migrate_from вместо hash_algorithm, кроме случаев использования хешировщика auto.

Обновите пароль

После успешного входа в систему, система Безопасности проверяет, доступен ли лучший алгоритм для хеширования пароля пользователя. Если доступен, то она хеширует правильный пароль, используя новый хеш. Если вы используете аутентификатор Guard, сначала вам нужно предоставить изначальный пароль системе Безопасности.

Вы можете подключить поведение обновления, реализовав, как этот новохешированный пароль должен быть сохранен:

После этого, вы закончили, и пароли всегда будут хешированы максимально безопасно!

Предоставьте пароль при использовании Guard

Когда вы использоуете пользовательский аутентификатор guard, вам нужно реализовать PasswordAuthenticatedInterface. Этот интерфейс определяет метод getPassword(), который возвращает пароль для этого запроса входа в систему. Этот пароль используется в процессе миграции:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// src/Security/CustomAuthenticator.php
namespace App\Security;

use Symfony\Component\Security\Guard\PasswordAuthenticatedInterface;
// ...

class CustomAuthenticator extends AbstractGuardAuthenticator implements PasswordAuthenticatedInterface
{
    // ...

    public function getPassword($credentials): ?string
    {
        return $credentials['password'];
    }
}

Обновите пароль при использовании Doctrine

При использовании сущности поставщика пользователей, реализуйте PasswordUpgraderInterface в UserRepository (см. документацию Doctrine, чтобы получить информацию о том, как создать этот класс, если он еще не создан). Этот интерфейс реализует хранение новосозданного хеша паролей:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// src/Repository/UserRepository.php
namespace App\Repository;

// ...
use Symfony\Component\Security\Core\User\PasswordUpgraderInterface;

class UserRepository extends EntityRepository implements PasswordUpgraderInterface
{
    // ...

    public function upgradePassword(UserInterface $user, string $newHashedPassword): void
    {
        // установите новохешированный пароль в объекте User
        $user->setPassword($newHashedPassword);

        // выполните запросы в БД
        $this->getEntityManager()->flush();
    }
}

Обновите пароль при использовании пользовательского поставщика пользователей

Если вы используете пользовательского поставщика пользователей, реализуйте PasswordUpgraderInterface в поставщике пользователей:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// src/Security/UserProvider.php
namespace App\Security;

// ...
use Symfony\Component\Security\Core\User\PasswordUpgraderInterface;

class UserProvider implements UserProviderInterface, PasswordUpgraderInterface
{
    // ...

    public function upgradePassword(UserInterface $user, string $newHashedPassword): void
    {
        // установите новохешированный пароль в объекте User
        $user->setPassword($newHashedPassword);

        // ... сохраните новый пароль
    }
}

Запустите миграцию паролей из пользовательского хешировщика

Если вы используете пользовательский хешировщик паролей, вы можете вызвать миграцию паролей, вернув true в методе needsRehash():

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// src/Security/CustomPasswordHasher.php
namespace App\Security;

// ...
use Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface;

class CustomPasswordHasher implements UserPasswordHasherInterface
{
    // ...

    public function needsRehash(string $hashed): bool
    {
        // проверить, хешируется ли текущий пароль с использованием устаревшего хешировщика
        $hashIsOutdated = ...;

        return $hashIsOutdated;
    }
}