Files
ipam_control/docs/changes/027-login-ip-serialization/PLAN.md
T
ayurishchevandClaude Opus 5.5 03d727e496 Задачи 025-030: ёмкость префиксов, политика входа, дерево префиксов
Повторный анализ кодовой базы (docs/reviews/2026-09-26-codebase-review-2.md) и доработки:
025 Ёмкость префикса — размер его подсети (а не сумма листьев); «Обзор» считает ёмкость
    по корневым активным IPv4-префиксам и адреса внутри них.
026 Политика блокировки входа: 5 неудач на логин+IP, 20 на IP, 50 на логин со всех IP,
    кроме известных IP (known_logins, миграция 0009) — владельца нельзя заблокировать анонимно.
027 Сериализация попыток входа по IP (advisory-lock после блокировки логина).
028 UI «Префиксы»: загрузка всех страниц (до 20 000), счётчики по total, предупреждение об усечении.
029 Advisory-lock по VRF для операций, меняющих дерево префиксов и раскладку адресов.
030 Исправление замечаний ревью 025-029: _lock_prefix (VRF блокируется до чтения префикса,
    409 при одновременном переносе), константы политики входа перенесены в app/services.py.

Тесты: 14 passed (проверка ёмкости родителя приведена к семантике 025); сквозные сценарии
и гонки — docs/reviews/2026-09-26-changes-025-029-review.md, 2026-09-27-changes-030-review.md.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-27 08:28:50 +03:00

2.2 KiB

Сериализация попыток входа по IP (изменение 027)

Находка № 7 из docs/reviews/2026-09-26-codebase-review-2.md, серьёзность — низкая. Выполняется вместе с 026 (тот же файл).

Context

Изменение 024 сериализует попытки одного логина (pg_advisory_xact_lock(hashtext(логин))). Параллельные попытки разных логинов с одного IP проходят проверку лимита по IP одновременно, и порог 20 можно превысить на степень параллелизма.

Решение (app/api/v1/auth.py, login)

  1. После блокировки по логину и до _retry_after — вторая блокировка pg_advisory_xact_lock(hashtext('ip:' || ip)), если ip известен. Порядок всегда «логин, затем IP»: IP-блокировка берётся последней, поэтому цикл ожидания невозможен.
  2. Использовать двухаргументную форму advisory-lock с отдельными пространствами ключей, чтобы исключить коллизии между логинами и IP: pg_advisory_xact_lock(<LOGIN_NS>, hashtext(name)) и pg_advisory_xact_lock(<IP_NS>, hashtext(ip)); константы пространств — в auth.py (например, 7031 и 7032).
  3. Комментарий в коде: цена — попытки с одного IP (в том числе за NAT) обрабатываются по одной, время ответа при массовом входе растёт на время argon2.

Файлы

app/api/v1/auth.py, README.md (одна фраза в абзаце «Вход»).

Проверка

16 параллельных неверных входов на 16 разных несуществующих логинов с одного IP при заранее вставленных 15 неудачах этого IP → проверено не больше 5 паролей (в login_attempts добавилось ≤ 5 записей), остальные — 429.