Миграция пользователей на безопасный алгоритм хеширования в Symfony

Ваше приложение может использовать старый, небезопасный алгоритм хеширования для хранения пароля, такой как MD5 (без использования соли)

Эта статья объясняет как преобразовать уже имеющиеся пароли, зашифрованные уязвимым алгоритмом в пароли зашифрованные с использованием безопасного метода хеширования (например с использованием Bcrypt )

Что бы решить проблему, мы сделаем конвертацию на лету, когда пользователь успешно входит в систему. Будем использовать интерфейс EncoderAwareInterface

login listener и использовать не очень хорошо известные параметры в security.yml.

 

Аутентификация до миграции

Если ваше приложение использует зашифрованные при помощи MD5 пароли, файл security.yml будет выглядеть примерно так что бы аутентификация Symfony работала

# app/config/security.yml
security:  
    encoders:
        AppBundle\Entity\User:
            algorithm: md5
            encode_as_base64: false
            iterations:       1

В этой статье, мы предполагаем что сущность User выглядит следующим образом:

# src/AppBundle/Entity/User.php

Все пользователи могут выполнять вход, вне зависимости от используемого алгоритма шифрования.

Добавляем «слушатель», который будет выполнять миграцию

Мы присоединим слушатель на событие Symfony security.interactive_login это событие срабатывает, когда пользователь выполнил успешный вход.

Для начала определим этот слушатель в файле services.yml file:

Declare first the listener in the services.yml file:

# app/config/services.yml
services:  
    app.login_listener:
        class: AppBundle\EventListener\LoginListener
        tags:
            - { name: kernel.event_listener, event: security.interactive_login }
        arguments:
            - "@security.encoder_factory"
            - "@doctrine.orm.entity_manager"

Создадим слушатель

# src/AppBundle/EventListener/LoginListener.php
<?php namespace AppBundle\EventListener; use Doctrine\Common\Persistence\ObjectManager; use Symfony\Component\Security\Core\Encoder\EncoderFactoryInterface; use Symfony\Component\Security\Http\Event\InteractiveLoginEvent; class LoginListener { private $encoderFactory; private $om; public function __construct(EncoderFactoryInterface $encoderFactory, ObjectManager $om) { $this->encoderFactory = $encoderFactory;
        $this->om = $om;
    }

    public function onSecurityInteractiveLogin(InteractiveLoginEvent $event)
    {
        $user = $event->getAuthenticationToken()->getUser();
        $token = $event->getAuthenticationToken();

        // Migrate the user to the new hashing algorithm if is using the legacy one
        if ($user->hasLegacyPassword()) {
            // Credentials can be retrieved thanks to the false value of
            // the erase_credentials parameter in security.yml
            $plainPassword = $token->getCredentials();

            $user->setOldPassword(null);
            $encoder = $this->encoderFactory->getEncoder($user);

            $user->setPassword(
                $encoder->encodePassword($plainPassword, $user->getSalt())
            );

            $this->om->persist($user);
            $this->om->flush();
        }

        // We don't need any more credentials
        $token->eraseCredentials();
    }
}

Этот слушатель обновляет пароль пользователь только в случае если пользователь все еще использует устаревшую систему паролей.

Что бы перекодировать пароль, нам нужен незахешированный пароль, введенный пользователем, который по-умолчанию недоступен в  authentication token предоставленный объектом InteractiveLoginEvent. Что бы сделать его доступным, сделайте следующие изменения в файле  security.yml:

# app/config/security.yml
security:  
    erase_credentials: false
    # ...

Как только ваши пользователи будут входить, данные о них будут обновлены в базе данных, делая их более безопасными со временем. Однажды, основная часть пользователей хотя бы раз выполнит вход и вы сможете удалить колонку old_password и реализовать фичу «Забыли пароль?» для тех, кто не был мигирован.

Автор: Michaël Perrin, ссылка на оригинальный пост

Добавить комментарий