[CLOSED] after updating from OC3.0 to OC4.1, customer login password validation contain a bug
Posted: Thu Mar 13, 2025 2:52 pm
public function login(string $username, string $password): bool {
$user_query = $this->db->query("SELECT * FROM `" . DB_PREFIX . "user` WHERE `username` = '" . $this->db->escape($username) . "' AND `status` = '1'");
if ($user_query->num_rows) {
if (password_verify($password, $user_query->row['password'])) {
$rehash = password_needs_rehash($user_query->row['password'], PASSWORD_DEFAULT);
} elseif (isset($user_query->row['salt']) && $user_query->row['password'] == sha1($user_query->row['salt'] . sha1($user_query->row['salt'] . sha1($password)))) {
$rehash = true;
} elseif ($user_query->row['password'] == md5($password)) {
$rehash = true;
} else {
return false;
}
if ($rehash) {
$this->db->query("UPDATE `" . DB_PREFIX . "user` SET `password` = '" . $this->db->escape(password_hash($password, PASSWORD_DEFAULT)) . "' WHERE `user_id` = '" . (int)$user_query->row['user_id'] . "'");
}
$this->session->data['user_id'] = $user_query->row['user_id'];
$this->user_id = $user_query->row['user_id'];
$this->username = $user_query->row['username'];
$this->firstname = $user_query->row['firstname'];
$this->lastname = $user_query->row['lastname'];
$this->email = $user_query->row['email'];
$this->user_group_id = $user_query->row['user_group_id'];
$user_group_query = $this->db->query("SELECT `permission` FROM `" . DB_PREFIX . "user_group` WHERE `user_group_id` = '" . (int)$user_query->row['user_group_id'] . "'");
$permissions = json_decode($user_group_query->row['permission'], true);
if (is_array($permissions)) {
foreach ($permissions as $key => $value) {
$this->permission[$key] = $value;
}
}
return true;
} else {
return false;
}
}
above is the OC 4.1 customer login validating .
My system is updated from oc 3.0 to 4.1, and all the customer data are registered in oc 3.0 old system, in 3.0 system, table oc_customer has the salt field , and password is hashed by the salt field, and in oc 4.1 database, the field salt is removed.
The system's intended design is to ensure compatibility for users migrating from OpenCart 3.0. Upon a user's first login, if their password isn't encrypted using the OpenCart 4.0 method, the system attempts to validate it using the OpenCart 3.0 encryption method. If successful, the password is then rehashed using the new encryption method and updated in the database. However, during the validation of the old encryption method, the process involves two steps:
First, the system checks for the presence of a salt field. If it exists, the system uses this salt in conjunction with the password to perform the encryption and compares the result with the stored password hash.
If the salt field is absent, the system defaults to using MD5 encryption for validation.
The issue arises because, in OpenCart 3.0, passwords were encrypted using a method that incorporated the salt field. In contrast, OpenCart 4.0 has removed the salt field and relies solely on MD5 encryption. These differing encryption methods produce different hash results, leading to potential validation failures. Consequently, users who registered under the OpenCart 3.0 system might be unable to log in successfully on the OpenCart 4.0 system due to these discrepancies in password validation logic.
---
so ,how to resolve the problem?
$user_query = $this->db->query("SELECT * FROM `" . DB_PREFIX . "user` WHERE `username` = '" . $this->db->escape($username) . "' AND `status` = '1'");
if ($user_query->num_rows) {
if (password_verify($password, $user_query->row['password'])) {
$rehash = password_needs_rehash($user_query->row['password'], PASSWORD_DEFAULT);
} elseif (isset($user_query->row['salt']) && $user_query->row['password'] == sha1($user_query->row['salt'] . sha1($user_query->row['salt'] . sha1($password)))) {
$rehash = true;
} elseif ($user_query->row['password'] == md5($password)) {
$rehash = true;
} else {
return false;
}
if ($rehash) {
$this->db->query("UPDATE `" . DB_PREFIX . "user` SET `password` = '" . $this->db->escape(password_hash($password, PASSWORD_DEFAULT)) . "' WHERE `user_id` = '" . (int)$user_query->row['user_id'] . "'");
}
$this->session->data['user_id'] = $user_query->row['user_id'];
$this->user_id = $user_query->row['user_id'];
$this->username = $user_query->row['username'];
$this->firstname = $user_query->row['firstname'];
$this->lastname = $user_query->row['lastname'];
$this->email = $user_query->row['email'];
$this->user_group_id = $user_query->row['user_group_id'];
$user_group_query = $this->db->query("SELECT `permission` FROM `" . DB_PREFIX . "user_group` WHERE `user_group_id` = '" . (int)$user_query->row['user_group_id'] . "'");
$permissions = json_decode($user_group_query->row['permission'], true);
if (is_array($permissions)) {
foreach ($permissions as $key => $value) {
$this->permission[$key] = $value;
}
}
return true;
} else {
return false;
}
}
above is the OC 4.1 customer login validating .
My system is updated from oc 3.0 to 4.1, and all the customer data are registered in oc 3.0 old system, in 3.0 system, table oc_customer has the salt field , and password is hashed by the salt field, and in oc 4.1 database, the field salt is removed.
The system's intended design is to ensure compatibility for users migrating from OpenCart 3.0. Upon a user's first login, if their password isn't encrypted using the OpenCart 4.0 method, the system attempts to validate it using the OpenCart 3.0 encryption method. If successful, the password is then rehashed using the new encryption method and updated in the database. However, during the validation of the old encryption method, the process involves two steps:
First, the system checks for the presence of a salt field. If it exists, the system uses this salt in conjunction with the password to perform the encryption and compares the result with the stored password hash.
If the salt field is absent, the system defaults to using MD5 encryption for validation.
The issue arises because, in OpenCart 3.0, passwords were encrypted using a method that incorporated the salt field. In contrast, OpenCart 4.0 has removed the salt field and relies solely on MD5 encryption. These differing encryption methods produce different hash results, leading to potential validation failures. Consequently, users who registered under the OpenCart 3.0 system might be unable to log in successfully on the OpenCart 4.0 system due to these discrepancies in password validation logic.
---
so ,how to resolve the problem?