8.3 KiB
Аудит Redis — полный отчёт
Дата: 2026-02-28 Версия: v1.8.65 Тестовый сервер: Reddis main ovh (Redis 8.2.1, 27M+ ключей, 2.82GB RAM)
1. Живое тестирование через CLI
Работает корректно
| Команда | Результат |
|---|---|
--redis-info ALIAS |
Версия, память, клиенты, keyspace |
--redis-keys ALIAS "*" |
SCAN до 1000 ключей, сортировка |
--redis ALIAS "PING" |
True |
--redis ALIAS "DBSIZE" |
27199166 |
--redis ALIAS "GET key" |
Возвращает значение |
--redis ALIAS "SET key value" |
True |
--redis ALIAS "DEL key1 key2" |
Число удалённых |
--redis ALIAS "KEYS pattern" |
Список с нумерацией |
--redis ALIAS "INFO memory" |
Полный вывод секции |
--redis ALIAS "TYPE key" |
Тип данных |
--redis ALIAS "TTL key" |
Секунды / -1 |
--redis ALIAS "SELECT 1" |
True |
--redis ALIAS "MSET k1 v1 k2 v2" |
True |
--status (redis) |
ONLINE |
Сломано
| Команда | Ошибка | Баг |
|---|---|---|
SET key "hello world" |
syntax error |
#1 |
SET key '{"a":1, "b":2}' |
syntax error |
#1 |
| Любое значение с пробелами | syntax error |
#1 |
2. Найденные баги
БАГ #1 — КРИТИЧНЫЙ: Парсер команд ломает значения с пробелами
Файлы: tools/ssh.py:958, core/redis_client.py:78
Проблема: Используется command.split() вместо shlex.split().
# Текущий код:
parts = command.split()
# "SET key 'hello world'" → ['SET', 'key', "'hello", "world'"]
# Redis получает 4 аргумента вместо 3 → syntax error
Воздействие:
- Невозможно SET/GET значения с пробелами
- Невозможно работать с JSON-данными содержащими пробелы
- Невозможно выполнить EVAL с Lua-скриптами
- Сломаны команды с multi-word аргументами (SORT, CONFIG SET и др.)
Затронуты: CLI (tools/ssh.py) И GUI (core/redis_client.py → redis_tab.py)
БАГ #2 — СРЕДНИЙ: GUI stats показывает отформатированную строку
Файл: gui/tabs/redis_tab.py:192-208
Проблема: _refresh_stats() вызывает client.execute("DBSIZE"), который возвращает строку "(integer) 27199166" (уже отформатированную через _format()). Эта строка отображается как есть.
# redis_tab.py:198
keys_count = client.execute("DBSIZE") # Returns "(integer) 27199166"
keys_text = str(keys_count) # → "(integer) 27199166" in label
Для INFO memory проблема другая:
# redis_tab.py:201
info = client.execute("INFO memory")
# _format() превращает dict в строку, но без \r\n
# Поиск по \r\n ничего не найдёт → memory = "—" всегда
for line in info.split("\r\n"): # \r\n не найдётся!
if line.startswith("used_memory_human:"):
memory = line.split(":")[1].strip()
Воздействие: Статистика в GUI:
- Keys показывает
(integer) 27199166вместо27199166 - Memory всегда показывает
—(парсинг не находит\r\n)
БАГ #3 — СРЕДНИЙ: GUI RedisClient не поддерживает SSL
Файл: core/redis_client.py:35-43
Проблема: В конструкторе redis.Redis() отсутствует параметр ssl.
# redis_client.py:35-43
self._conn = r.Redis(
host=self._host,
port=self._port,
password=self._password,
db=self._db,
decode_responses=True,
socket_timeout=5,
socket_connect_timeout=5,
# ❌ ОТСУТСТВУЕТ: ssl=...
)
При этом CLI (tools/ssh.py:955-956) SSL поддерживает:
ssl_enabled = server.get("ssl", False)
r = redis_lib.Redis(..., ssl=ssl_enabled)
Воздействие: GUI не может подключиться к Redis с TLS/SSL.
Связанная проблема: В server_dialog.py поле use_ssl/ssl НЕ включено в FIELD_MAP["redis"]:
"redis": ["password", "db_index"] # нет ssl!
Даже если добавить SSL в RedisClient, пользователь не сможет включить его в UI.
БАГ #4 — НИЗКИЙ: CLI Redis ошибки выдают сырой traceback
Файл: tools/ssh.py:957-962
Проблема: r.execute_command() не обёрнут в try-except.
# Текущий код:
result = r.execute_command(*parts) # При ошибке → необработанное исключение
Пример: HGETALL на string-ключе:
ERROR: ResponseError: WRONGTYPE Operation against a key holding the wrong kind of value
Выводится как traceback с двойным повтором вместо читаемого сообщения.
БАГ #5 — НИЗКИЙ: Двойной PING при status check
Файл: core/status_checker.py:98-110
def _check_redis(self, server: dict) -> bool:
client = RedisClient(server)
result = client.connect() # ← PING #1 внутри connect()
if result:
ok = client.check_connection() # ← PING #2
client.disconnect()
return ok
return False
connect() уже делает self._conn.ping() → True. Потом check_connection() вызывает self._conn.ping() ещё раз.
БАГ #6 — НИЗКИЙ: CLI status для Redis без try-except
Файл: tools/ssh.py:698-703
if stype == "redis":
r = redis_lib.Redis(...)
r.ping() # ← Нет try-except! Если offline → traceback
r.close()
return "ONLINE"
Сравни с SQL, где conn.close() в finally. Здесь если ping() упадёт, r.close() не вызовется.
ПРОБЛЕМА #7 — Дублирование кода подключения
Файлы: tools/ssh.py:946-956, tools/ssh.py:978-986, tools/ssh.py:1009-1017
Три функции (run_redis_cmd, redis_info, redis_keys) создают одинаковое подключение к Redis копипастом:
import redis as redis_lib
host = server["ip"]
port = server.get("port", 6379)
password = server.get("password", "") or None
db_index = server.get("db_index", 0)
ssl_enabled = server.get("ssl", False)
r = redis_lib.Redis(host=host, port=port, ...)
Этот блок повторяется 3 раза. Вынести в хелпер.
3. Карта проблем по файлам
| Файл | Строки | Баги |
|---|---|---|
tools/ssh.py |
958 | #1 (split), #4 (error handling), #6 (status), #7 (copypaste) |
core/redis_client.py |
78, 35-43 | #1 (split), #3 (no SSL) |
gui/tabs/redis_tab.py |
192-208 | #2 (stats parsing) |
core/status_checker.py |
98-110 | #5 (double ping) |
gui/server_dialog.py |
22 | #3 (no ssl field for redis) |
4. Влияние на пользователей
| Сценарий | Статус | Причина |
|---|---|---|
| Простые команды (GET/SET/DEL) | ✅ Работает | Нет пробелов |
| Команды со значениями с пробелами | ❌ Сломано | Баг #1 |
| JSON-данные с пробелами | ❌ Сломано | Баг #1 |
| GUI статистика Keys | ⚠️ Некорректно | Баг #2 |
| GUI статистика Memory | ❌ Всегда "—" | Баг #2 |
| SSL-подключение через GUI | ❌ Невозможно | Баг #3 |
| SSL-подключение через CLI | ✅ Работает | — |
| Ошибки в CLI | ⚠️ Нечитаемые | Баг #4 |
| Status check | ✅ Работает (с оверхедом) | Баг #5 |