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)
...