diff --git a/ajax/login.php b/ajax/login.php index 6d1ba3d..8162dc7 100755 --- a/ajax/login.php +++ b/ajax/login.php @@ -1,30 +1,72 @@ 255 || strlen($password) > 255) { + echo 'fail[#]'; + exit; + } + + // Rate limiting básico (máximo 5 intentos por minuto) + $rateLimitKey = 'login_attempts_' . $_SERVER['REMOTE_ADDR']; + if (!isset($_SESSION[$rateLimitKey])) { + $_SESSION[$rateLimitKey] = ['count' => 0, 'time' => time()]; + } + + $attempts = $_SESSION[$rateLimitKey]; + if ($attempts['count'] >= 5 && (time() - $attempts['time']) < 60) { + echo 'fail[#]'; + exit; + } + + // Incrementar contador de intentos + $_SESSION[$rateLimitKey]['count']++; + if (time() - $_SESSION[$rateLimitKey]['time'] > 60) { + $_SESSION[$rateLimitKey] = ['count' => 1, 'time' => time()]; + } + + // Realizar login $empresa->setEmail($email); $empresa->setPassword($password); - // El método DoLogin ahora debe obtener el empresaId desde la base de datos - // basado en el email y password del usuario if(!$empresa->DoLogin()) { - // If DoLogin itself sets errors (e.g., incorrect credentials), print them here + // Si el login es exitoso, resetear contador if($empresa->Util()->GetError()){ $empresa->Util()->PrintErrors(); } @@ -32,7 +74,9 @@ } else { + // Resetear contador de intentos en login exitoso + unset($_SESSION[$rateLimitKey]); echo 'ok[#]ok'; } - - ?> \ No newline at end of file + + ?> \ No newline at end of file diff --git a/ajax/usuarios.php b/ajax/usuarios.php index 144795c..eef8ba3 100755 --- a/ajax/usuarios.php +++ b/ajax/usuarios.php @@ -59,6 +59,8 @@ switch($_POST["type"]) break; case "saveEditUsuario": + + $email = trim($_POST['email']); $usuario->setTipo($_POST['tipo']); $usuario->setUsuarioId($_POST['usuarioId']); diff --git a/classes/empresa.class.php b/classes/empresa.class.php index 5febf12..12663fa 100755 --- a/classes/empresa.class.php +++ b/classes/empresa.class.php @@ -391,10 +391,9 @@ $this->Util()->ValidateMail($value, "Email"); } } - // CAMBIO CRÍTICO: Obtener empresaId dinámicamente del usuario con BD real - $sql = "SELECT usuarioId, empresaId FROM usuario + // CAMBIO DE SEGURIDAD: Obtener usuario por email primero (sin contraseña) + $sql = "SELECT usuarioId, empresaId, password FROM usuario WHERE email = '".$this->email."' - AND password = '".$this->password."' AND baja = '0'"; $result = $masterConnection->query($sql); @@ -410,7 +409,21 @@ $this->Util()->ValidateMail($value, "Email"); { return false; } + } + + // Verificar contraseña usando método seguro + $usuario = new Usuario(); + $usuario->setUsuarioId($row['usuarioId']); + if(!$usuario->verifyPassword($this->password, $row['password'])) + { + unset($_SESSION["loginKey"]); + unset($_SESSION["empresaId"]); + $this->Util()->setError(10006, "error"); + if($this->Util()->PrintErrors()) + { + return false; + } } // Obtener datos del usuario de forma segura diff --git a/classes/usuario.class.php b/classes/usuario.class.php index 030842a..bbf9d07 100755 --- a/classes/usuario.class.php +++ b/classes/usuario.class.php @@ -147,7 +147,40 @@ class Usuario extends Main public function setPassword($value) { - $this->passwd = $value; + // Si la contraseña ya está hasheada (empieza con $2y$), la guardamos directamente + if(preg_match('/^\$2y\$/', $value)) { + $this->passwd = $value; + } else { + // Si no, la hasheamos + $this->passwd = password_hash($value, PASSWORD_DEFAULT); + } + } + + // Método para verificar contraseña (usado en login) + public function verifyPassword($plainPassword, $hashedPassword) + { + // Si la contraseña almacenada está en texto plano (migración) + if(!preg_match('/^\$2y\$/', $hashedPassword)) { + // Verificar contra texto plano y hashear si coincide + if($plainPassword === $hashedPassword) { + // Actualizar a hash + $this->passwd = password_hash($plainPassword, PASSWORD_DEFAULT); + $this->updatePasswordHash(); + return true; + } + return false; + } + + // Verificación normal con hash + return password_verify($plainPassword, $hashedPassword); + } + + // Método para actualizar el hash en la base de datos + private function updatePasswordHash() + { + $db = new DB(true); + $db->setQuery("UPDATE usuario SET password = '".$this->passwd."' WHERE usuarioId = '".$this->usuarioId."'"); + $db->UpdateData(); } public function setTipo($value) @@ -302,8 +335,9 @@ class Usuario extends Main } $db = new DB(true); - $db->setQuery(" - UPDATE usuario SET + + // Construir consulta SQL condicional para la contraseña + $sql = "UPDATE usuario SET nombre = '".$this->nombre."', apellidos = '".$this->apellidos."', calle = '".$this->calle."', @@ -321,12 +355,18 @@ class Usuario extends Main noImss = '".$this->noImss."', curp = '".$this->curp."', rfc = '".$this->rfc."', - email = '".$this->email."', - password = '".$this->passwd."', - `type` = '".$this->tipo."', + email = '".$this->email."'"; + + // Solo actualizar contraseña si se estableció una nueva + if (!empty($this->passwd)) { + $sql .= ", password = '".$this->passwd."'"; + } + + $sql .= ", `type` = '".$this->tipo."', sucursalId = '".$this->sucursalId."' - WHERE usuarioId = '".$this->usuarioId."'" - ); + WHERE usuarioId = '".$this->usuarioId."'"; + + $db->setQuery($sql); $db->UpdateData(); $this->Util()->setError(20019, "complete"); diff --git a/modules/login.php b/modules/login.php index 0b5bbcc..eea81d7 100755 --- a/modules/login.php +++ b/modules/login.php @@ -1,9 +1,15 @@ setQuery("SELECT * FROM empresa"); -$result = $db->GetResult(); + // Generar token CSRF para protección + if (empty($_SESSION['csrf_token'])) { + $_SESSION['csrf_token'] = bin2hex(random_bytes(32)); + } -$smarty->assign("empresas", $result); + $db = new DB(true); // Usar master connection + $db->setQuery("SELECT * FROM empresa"); + $result = $db->GetResult(); -?> + $smarty->assign("empresas", $result); + $smarty->assign("csrf_token", $_SESSION['csrf_token']); + + ?> diff --git a/modules/usuarios-editar.php b/modules/usuarios-editar.php index e295af6..24a04e4 100755 --- a/modules/usuarios-editar.php +++ b/modules/usuarios-editar.php @@ -35,7 +35,31 @@ $usuario->setCurp($_POST['curp']); $usuario->setRfc($_POST['rfc']); $usuario->setEmail($_POST['email']); - $usuario->setPassword($_POST['password']); + + // Solo actualizar contraseña si se proporciona una nueva + $newPassword = trim($_POST['password']); + $confirmPassword = trim($_POST['password_confirm']); + + if (!empty($newPassword)) { + // Validar que las contraseñas coincidan + if ($newPassword !== $confirmPassword) { + $smarty->assign("error", "Las contraseñas no coinciden"); + $smarty->assign("info", $_POST); + $smarty->display('templates/forms/editar-usuario.tpl'); + exit; + } + + // Validar longitud mínima + if (strlen($newPassword) < 6) { + $smarty->assign("error", "La contraseña debe tener al menos 6 caracteres"); + $smarty->assign("info", $_POST); + $smarty->display('templates/forms/editar-usuario.tpl'); + exit; + } + + $usuario->setPassword($newPassword); + } + $usuario->setSucursalId($_POST['sucursalId']); $usuario->Update(); diff --git a/templates/forms/editar-usuario.tpl b/templates/forms/editar-usuario.tpl index ff84324..23c5261 100755 --- a/templates/forms/editar-usuario.tpl +++ b/templates/forms/editar-usuario.tpl @@ -85,11 +85,14 @@ - Contraseña: - + Nueva Contraseña: + + +
Si no desea cambiar la contraseña, deje este campo vacío. + - - + Confirmar: + .:: IDENTIFICACION OFICIAL ::. diff --git a/templates/login.tpl b/templates/login.tpl index b7ad17b..4535807 100755 --- a/templates/login.tpl +++ b/templates/login.tpl @@ -11,12 +11,13 @@

-
-

-

+ -

+ +