Документирован аудит Codex: HISTORY + ARCHITECTURE (раздел 8 — безопасность и конкуренция)
This commit is contained in:
@@ -188,3 +188,39 @@ SVC_ID = 1 — фиксированный сервис (Болванка)
|
||||
- Gunicorn multi-worker → общие данные через файлы + flock
|
||||
- `/tmp/` теряется при редеплое
|
||||
- User-Agent: `Mozilla/5.0` обязателен (DDoS-Guard)
|
||||
|
||||
---
|
||||
|
||||
## 8. Безопасность и конкуренция (аудит GPT-5.3-Codex, 2026-07-31)
|
||||
|
||||
Полный аудит 29 файлов (~6000 строк Python + vanilla JS). Исправлено в v1.2.19-v1.2.20.
|
||||
|
||||
### Защита от XSS (Frontend)
|
||||
|
||||
- **`_esc(s)` в utils.js** — HTML-escape: `&` → `&`, `"` → `"`, `<` → `<`
|
||||
Применяется ко ВСЕМ данным из API перед `innerHTML`.
|
||||
- **params в scenario-list.js** — `_esc(k)+'='+_esc(v)` (было `k+'='+v` без экранирования).
|
||||
- **JS injection в onclick** — имена сценариев с `'` теперь `replace(/'/g, "\\'")` перед
|
||||
вставкой в JS-строку внутри HTML-атрибута.
|
||||
|
||||
### Защита от гонок (Backend)
|
||||
|
||||
- **`_op_results`** — `threading.Lock()` вокруг всех операций чтения/записи/cleanup.
|
||||
`pop(k, None)` вместо `del dict[k]` — безопасно при конкурентном доступе.
|
||||
- **Advisory lock сценариев** — `pg_try_advisory_lock(hashtext('scenario:{clientId}:{stand}'))`
|
||||
атомарно проверяет и захватывает блокировку. `finally: unlock_scenario()` в `run_scenario()`.
|
||||
- **Tracker** — `_atomic_update()`: read→mutate→write под одним `fcntl.flock`.
|
||||
Исключает lost-update между `add()` и `remove()` из разных воркеров gunicorn.
|
||||
|
||||
### Защита от зависания (Frontend polling)
|
||||
|
||||
- **Счётчик ошибок** в `scenarioPollTimer` — после 5 последовательных ошибок:
|
||||
`stopScenarioPoll()` + `busy=false` + сообщение об ошибке.
|
||||
- **Generation token** в `scenario-form.js` — `_renderGen` предотвращает перезапись
|
||||
нового DOM старыми данными от async `loadStepParams()`.
|
||||
|
||||
### Известные ограничения
|
||||
|
||||
- **`_op_results` in-memory на воркер** — не shared между gunicorn-воркерами.
|
||||
При отсутствии stickiness статус может читаться из API fallback вместо кеша.
|
||||
Решение (отложено): Redis или общая таблица в БД для статусов операций.
|
||||
|
||||
Reference in New Issue
Block a user