Niszczenie sesji klienta w PrestaShop po zmianie hasła + jak nie robić refactoringu

W PrestaShop 1.7 po zmianie hasła klienta, jego sesje na innym komputerze są wciąż utrzymywane, co w może być uznawane jako błąd bezpieczeństwa. W tym wpisie pokaże jak to naprawić i skąd się to wzięło 🙂

TLDR - rozwiązanie problemu

Najprościej wylogować klienta kiedy jego hasło w cookie nie pasuje do hasła w bazie, wystarczy np. pod koniec pliku config.inc.php dodać:

if ($context->customer && $context->customer->isLogged() && !$context->cookie->isLogged()) {
    $context->cookie->logout();
    Tools::redirect('index.php');
}

Kod sprawdza, czy klient jest zalogowany tradycyjnie, sprawdza czy jest zalogowany ściśle (hasło pasuje) a jeśli nie to wylogowuje i przekierowuje do strony głównej.

Przyczyna problemu

Wydaje się, że domyślnym zachowaniem powinno być wylogowanie klienta na wszystkich urządzeniach po zmianie hasła. Dlaczego więc w PrestaShop 1.7 to tak nie działa?

Przyjrzyjmy się funkcji sprawdzającej zalogowanie (classes/Customer.php):

public function isLogged($withGuest = false)
{
    if (!$withGuest && $this->is_guest == 1) {
        return false;
    }

    /* Customer is valid only if it can be load and if object password is the same as database one */
    return $this->logged == 1 && $this->id && Validate::isUnsignedId($this->id) && Customer::checkPassword($this->id, $this->passwd);
}

Jak widać funkcja sprawdza, czy mamy instancje klienta, czy jest zalogowany i hasło ale hasło jest porównywane z hasłem instancji, a nie tym w cookie.

Podobna funkcja jest w klasie Cookie która we wcześniejszych wersjach była używana zamiast tej w klasie Customer:

public function isLogged($withGuest = false)
{
    Tools::displayAsDeprecated('Use Customer::isLogged() instead');
    if (!$withGuest && $this->is_guest == 1) {
        return false;
    }

    /* Customer is valid only if it can be load and if cookie password is the same as database one */
    if ($this->logged == 1 && $this->id_customer && Validate::isUnsignedId($this->id_customer) && Customer::checkPassword((int) ($this->id_customer), $this->passwd)) {
        return true;
    }

    return false;
}

Jak widać funkcje poza oznaczeniem deprecated są bliźniacze z jednym wyjątkiem, w tej pierwotnej hasło jest porównywane z tym w instancji Cookie (czyli ciasteczka) a w tej po refactoringu z tym w instancji klienta, co jest błędem:

...
Customer::checkPassword((int) ($this->id_customer), $this->passwd)
...

Dodaj komentarz

Twój adres e-mail nie zostanie opublikowany. Wymagane pola są oznaczone *