bump v0.90.0
This commit is contained in:
+75
-49
@@ -1,65 +1,91 @@
|
||||
# Отчёт об аудите (07.06.2026)
|
||||
# Отчёт об аудите безопасности и багах (07.06.2026)
|
||||
|
||||
## Найдено
|
||||
## 🔴 КРИТИЧЕСКИЕ (7)
|
||||
|
||||
### 🔴 Критичные
|
||||
### 1. Жестко заданный API ключ в конфигурации
|
||||
- **Файл:** [config.yaml](config.yaml#L5)
|
||||
- **Описание:** \`api_key: "sk-78ec529c1eba4ba69995091046c9fa33"\` — настоящий ключ DeepSeek находится непосредственно в репозитории.
|
||||
- **Влияние:** Экспозиция платного LLM, финансовый ущерб, возможность несанкционированного использования лимитов.
|
||||
|
||||
1. **Краш при отсутствии Bluetooth**
|
||||
- **Файл:** [android/app/src/main/java/ru/elmer/client/ui/MainActivity.kt](android/app/src/main/java/ru/elmer/client/ui/MainActivity.kt)
|
||||
- **Строки:** 155, 230, 310
|
||||
- **Описание:** Используется оператор `!!` для `btAdapter`. На устройствах без Bluetooth (или в эмуляторе) приложение упадёт при попытке проверить прибор или запустить сканирование.
|
||||
- **Как исправить:** Добавить проверку `if (btAdapter == null)` перед использованием и выводить сообщение об ошибке.
|
||||
### 2. check_same_thread=False в SQLite
|
||||
- **Файл:** [api/db.py](api/db.py#L20)
|
||||
- **Описание:** Использование \`check_same_thread=False\` без механизмов синхронизации в многопоточном Flask-приложении.
|
||||
- **Влияние:** Состояние гонки (Race conditions), повреждение базы данных при одновременной записи.
|
||||
|
||||
2. **Отсутствие аутентификации на сервере**
|
||||
- **Файл:** [api/routes.py](api/routes.py)
|
||||
- **Описание:** Эндпоинты `/api/v1/session/upload`, `/api/v1/chat` и `/api/v1/ping-llm` принимают запросы без проверки API-ключа. Клиент передаёт `X-Api-Key`, но сервер его игнорирует. Любой может отправлять запросы и тратить токены LLM.
|
||||
- **Как исправить:** Добавить декоратор `@api_key_required` или проверку заголовка в `before_request`.
|
||||
### 3. /api/v1/ping-llm без аутентификации тратит токены
|
||||
- **Файлы:** [api/ping.py](api/ping.py#L40-45), [web/script_endpoint.py](web/script_endpoint.py#L215-219)
|
||||
- **Описание:** Эндпоинт доступен без заголовка \`X-Api-Key\` и выполняет реальный запрос к LLM.
|
||||
- **Влияние:** Возможность DoS-атаки на кошелек API через бесконечные пинги.
|
||||
|
||||
3. **Состязание потоков (Race Condition) в ScriptRunnerService**
|
||||
- **Файл:** [android/app/src/main/java/ru/elmer/client/script/ScriptRunnerService.kt](android/app/src/main/java/ru/elmer/client/script/ScriptRunnerService.kt)
|
||||
- **Описание:** `onStartCommand` не проверяет, запущен ли уже процесс. Если дважды вызвать `startForegroundService` (нажав кнопку несколько раз), создадутся два конкурирующих потока `ScriptRunner`, которые будут одновременно работать с одним и тем же Bluetooth-сокетом.
|
||||
- **Как исправить:** В `startRun` проверять флаг `running` и игнорировать повторные запуски.
|
||||
### 4. Краш при отсутствии Bluetooth (Android)
|
||||
- **Файл:** [android/app/src/main/java/ru/elmer/client/ui/MainActivity.kt](android/app/src/main/java/ru/elmer/client/ui/MainActivity.kt)
|
||||
- **Описание:** Используется оператор \`!!\` для \`btAdapter\`. На устройствах без Bluetooth приложение упадёт.
|
||||
- **Влияние:** Нестабильность приложения на эмуляторах и старых устройствах.
|
||||
|
||||
4. **Логическая ошибка в выборе Bluetooth-устройства**
|
||||
- **Файл:** [android/app/src/main/java/ru/elmer/client/ui/MainActivity.kt](android/app/src/main/java/ru/elmer/client/ui/MainActivity.kt#L457)
|
||||
- **Описание:** Функция `findElmDevice()` при наличии двух и более устройств показывает диалог, но возвращает `null` немедленно. Стейт-машина (`checkElm`, `scanDtc`) видит `null` и прерывает работу с ошибкой «ELM не найден».
|
||||
- **Как исправить:** Перестроить логику: диалог выбора должен вызываться отдельно, сохранять `elmDevice`, и только потом запускать операции.
|
||||
### 5. Отсутствие аутентификации на критичных эндпоинтах
|
||||
- **Файл:** [api/routes.py](api/routes.py#L245), [api/routes.py](api/routes.py#L292)
|
||||
- **Описание:** Эндпоинты \`POST /api/v1/elm/probe\` и \`GET /api/v1/elm/profile/<mac>\` не защищены API-ключом.
|
||||
- **Влияние:** Идентификация структуры OBD-профилей любых пользователей.
|
||||
|
||||
### 🟡 Средние
|
||||
### 6. Дублирование API с разной логикой
|
||||
- **Файлы:** [web/script_endpoint.py](web/script_endpoint.py) vs [api/routes.py](api/routes.py)
|
||||
- **Описание:** Маршрут \`/api/v1/session/upload\` реализован дважды. В \`web/\` версии отсутствует проверка идемпотентности (\`request_id\`).
|
||||
- **Влияние:** Неконсистентное поведение, дублирование LLM-запросов при ретраях из мобильного приложения.
|
||||
|
||||
5. **Утечка памяти в ElmChecker**
|
||||
- **Файл:** [android/app/src/main/java/ru/elmer/client/elm/ElmChecker.kt](android/app/src/main/java/ru/elmer/client/elm/ElmChecker.kt)
|
||||
- **Описание:** Список `logLines` является членом класса. В `MainActivity` экземпляр `elmChecker` переиспользуется. Приложение копит логи всех операций в памяти до своей гибели.
|
||||
- **Как исправить:** Очищать `logLines` в начале каждой операции или переносить лог в локальную переменную метода `run()`.
|
||||
### 7. Состязание потоков в ScriptRunnerService (Android)
|
||||
- **Файл:** [android/app/src/main/java/ru/elmer/client/script/ScriptRunnerService.kt](android/app/src/main/java/ru/elmer/client/script/ScriptRunnerService.kt)
|
||||
- **Описание:** Повторный запуск сервиса создает новый поток \`ScriptRunner\`, конкурирующий за Bluetooth-сокет.
|
||||
|
||||
6. **Утечка курсоров в БД**
|
||||
- **Файл:** [android/app/src/main/java/ru/elmer/client/db/SessionDb.kt](android/app/src/main/java/ru/elmer/client/db/SessionDb.kt)
|
||||
- **Описание:** Методы `getResponses`, `getSessions`, `getPendingSessions` вызывают `cursor.close()` в конце цикла, но не в `finally`. При ошибке чтения курсор останется открытым.
|
||||
- **Как исправить:** Использовать конструкцию `.use { ... }` (в Kotlin для `Cursor` доступно начиная с определенных версий) или `try { ... } finally { cursor.close() }`.
|
||||
---
|
||||
|
||||
7. **Не включены Foreign Keys**
|
||||
- **Файл:** [android/app/src/main/java/ru/elmer/client/db/SessionDb.kt](android/app/src/main/java/ru/elmer/client/db/SessionDb.kt)
|
||||
- **Описание:** Несмотря на наличие `REFERENCES sessions(id)`, SQLite в Android по умолчанию не проверяет целостность связей.
|
||||
- **Как исправить:** Добавить `db.setForeignKeyConstraintsEnabled(true)` в `onConfigure`.
|
||||
## 🟡 ВАЖНЫЕ (10)
|
||||
|
||||
8. **Слепой выбор устройства в сервисе**
|
||||
- **Файл:** [android/app/src/main/java/ru/elmer/client/script/ScriptRunnerService.kt](android/app/src/main/java/ru/elmer/client/script/ScriptRunnerService.kt#L143)
|
||||
- **Описание:** Сервис берёт `bonded[0]` — первое попавшееся сопряжённое устройство. Это могут быть наушники или магнитола.
|
||||
- **Как исправить:** Передавать MAC-адрес выбранного ELM через `Intent`.
|
||||
### 8. Database.close() не гарантирован в web/
|
||||
- **Файл:** [web/script_endpoint.py](web/script_endpoint.py#L117-120)
|
||||
- **Описание:** Соединение с БД открывается, но не закрывается в блоке \`finally\`.
|
||||
- **Влияние:** Утечка дескрипторов файлов и соединений SQLite.
|
||||
|
||||
9. **Отсутствие лимита на размер запроса**
|
||||
- **Файл:** [api/routes.py](api/routes.py)
|
||||
- **Описание:** Сервер принимает список `responses` любого размера. Злоумышленник может отправить миллион строк, вызвав OOM или переполнение диска логами.
|
||||
- **Как исправить:** Проверять `len(responses)` перед обработкой.
|
||||
### 9. Отсутствие checkpoint для WAL в SQLite
|
||||
- **Файл:** [api/db.py](api/db.py#L22)
|
||||
- **Описание:** Режим WAL включен, но \`wal_checkpoint\` никогда не вызывается явно. Журналы могут расти бесконечно.
|
||||
|
||||
### 🟢 Косметика
|
||||
### 10. Утечка курсоров в БД (Android)
|
||||
- **Файл:** [android/app/src/main/java/ru/elmer/client/db/SessionDb.kt](android/app/src/main/java/ru/elmer/client/db/SessionDb.kt)
|
||||
- **Описание:** Курсоры закрываются только в конце успешных циклов, а не в \`finally\`.
|
||||
|
||||
10. **Неиспользуемые переменные**
|
||||
- В `ElmProtocol.kt` константа `INIT_TIMEOUT` и другие не используются.
|
||||
- В `MainActivity.kt` список `chatHistory` хранится в памяти, но не восстанавливается после `onSaveInstanceState`.
|
||||
### 11. Не включены Foreign Keys (Android)
|
||||
- **Файл:** [android/app/src/main/java/ru/elmer/client/db/SessionDb.kt](android/app/src/main/java/ru/elmer/client/db/SessionDb.kt)
|
||||
- **Описание:** SQLite игнорирует \`REFERENCES\` без явной команды \`PRAGMA foreign_keys = ON\`.
|
||||
|
||||
11. **Устаревший API**
|
||||
- `BluetoothAdapter.getDefaultAdapter()` помечен как Deprecated. В современных Android рекомендуется использовать `BluetoothManager`.
|
||||
### 12. Раскрытие sensitive info в ошибках
|
||||
- **Файлы:** [web/script_endpoint.py](web/script_endpoint.py#L127), [api/ping.py](api/ping.py#L48)
|
||||
- **Описание:** \`str(e)\` пробрасывается клиенту, может содержать детали API или токены.
|
||||
|
||||
12. **Бесполезный пинг LLM**
|
||||
- Эндпоинт `/api/v1/ping-llm` делает реальный `diagnose`, что стоит денег (токенов). Кэш есть, но при перезапуске сервера или по таймауту он всё равно будет жечь токены на "пустые" проверки.
|
||||
### 13. Нет лимита на размер payload
|
||||
- **Описание:** Сервер принимает JSON любого объема, что ведет к OOM (Out Of Memory).
|
||||
|
||||
### 14. Нет rate-limiting
|
||||
- **Описание:** Отсутствует защита от перебора ключей и спама запросами.
|
||||
|
||||
### 15. Отсутствие CORS ограничений
|
||||
- **Файл:** [web/app.py](web/app.py#L48)
|
||||
- **Описание:** Flask слушает на \`0.0.0.0\`, разрешая запросы с любых источников.
|
||||
|
||||
### 16. Уязвимость потокобезопасности AndrOBD
|
||||
- **Файл:** [obd/protocol.py](obd/protocol.py#L114-121)
|
||||
- **Описание:** Метод \`send()\` не синхронизирован, состояние протокола может быть повреждено при параллельном доступе.
|
||||
|
||||
### 17. Слепой выбор Bluetooth-устройства в сервисе (Android)
|
||||
- **Файл:** [android/app/src/main/java/ru/elmer/client/script/ScriptRunnerService.kt](android/app/src/main/java/ru/elmer/client/script/ScriptRunnerService.kt#L143)
|
||||
- **Описание:** Берется первое сопряженное устройство (\`bonded[0]\`), что часто ошибочно.
|
||||
|
||||
---
|
||||
|
||||
## 📋 ЗАМЕЧАНИЯ ПО АРХИТЕКТУРЕ
|
||||
- **Dynamic Imports:** В \`web/script_endpoint.py\` импорты используют \`elmer.*\`, что может конфликтовать с установленными пакетами.
|
||||
- **Git Hygiene:** Файл \`config.yaml\` содержит секреты и должен быть добавлен в \`.gitignore\` с предоставлением \`config.yaml.example\`.
|
||||
- **Логирование:** Недостаточно информации для трассировки багов пользователя (отсутствуют IP и User-Agent в логах сессий).
|
||||
|
||||
---
|
||||
*Дата аудита: 07.06.2026*
|
||||
*Инструмент: GitHub Copilot (Gemini 3 Flash)*
|
||||
|
||||
Reference in New Issue
Block a user