Files
ripe-cidr-collector/docs/plan-input-hardening.md
ayurishchevandClaude Sonnet 5 46d56654d8 Harden input handling and filter non-global DNS addresses
X-API-Key compared as bytes (401 instead of 500 on non-ASCII), strict
parsing of the diff "since" parameter (400 instead of 500), FQDN
resolution keeps only global addresses (allow_non_global_ips to opt out).
Adds the code review report and the plan/summary for this change.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-21 09:42:51 +03:00

4.6 KiB

План: безопасность ввода и данных (п. 2-4 ревью)

Источник: docs/review-2026-09-21.md, находки 2, 3 и 4.

Цель

Некорректный ввод не приводит к ответу 500, а адреса, которые не должны попадать в правила файрвола (loopback, частные, 0.0.0.0), не попадают в выдачу.

Дизайн

Находка 2: заголовок X-API-Key

  • Сравнение токенов выполняется по байтам (encode("utf-8") обеих сторон): secrets.compare_digest для str принимает только ASCII и падает на других символах.
  • Результат: любой неверный ключ, в том числе нелатинский, даёт 401; поведение с верным ключом и без токена в окружении (503) не меняется.

Находка 3: параметр since (GET /addresses/diff)

  • Курсором считается строка из ASCII-цифр длиной до 30 символов (isascii() and isdigit()); более длинная или с юникод-цифрами трактуется как некорректное значение.
  • Разбор времени защищён от OverflowError (крайние даты с поясом) вместе с ValueError.
  • Все некорректные значения дают 400 с прежним текстом; 410 остаётся для корректных, но вышедших за журнал значений (в том числе очень больших курсоров до 30 цифр).

Находка 4: фильтрация DNS-адресов

  • FQDNCollector.resolve_fqdn оставляет только глобальные адреса (ipaddress.ip_address(...).is_global; зона IPv6 %if отбрасывается перед разбором). Отфильтрованные значения пишутся в лог (WARNING, с перечнем).
  • Если после фильтрации адресов не осталось, поведение как при ошибке DNS: предупреждение, TTL не применяется, данные не удаляются.
  • Обходной путь для внутренних имён: ключ allow_non_global_ips в config.json (по умолчанию false; true отключает фильтр).
  • Ранее собранные неглобальные адреса не удаляются сразу: они истекают по ttl_days (для немедленной очистки - DELETE /fqdns/<имя>?purge=true и повторное добавление).

Изменения

  1. api_server.py: сравнение токена по байтам; parse_since (ограничение длины, ASCII-цифры, перехват OverflowError).
  2. cidr_collector.py: фильтр в resolve_fqdn, чтение allow_non_global_ips.
  3. README.md: ограничения since (400), фильтрация адресов и ключ allow_non_global_ips, ключ в описании config.json.
  4. docs/review-2026-09-21.md: статусы находок; итоги в docs/summary-input-hardening.md.
  5. Тесты (2, всего 22): API (нелатинский ключ даёт 401; since с юникод-цифрой, длинным числом и крайней датой даёт 400); сборщик (смесь глобальных, частных, loopback и зональных адресов фильтруется, с allow_non_global_ips остаётся всё, если ничего не осталось - пустой результат).

Не входит

Находка 1 (пустая выдача после порчи без копий) - отдельное решение по поведению; находки 5-10 - отдельные доработки.

Проверка

Тесты в контейнере; вручную в контейнерном окружении повторить запросы из ревью (since=², длинное число, 0001-01-01T00:00:00+05:00, нелатинский X-API-Key), для DNS - сбор на копии с подставленными ответами getaddrinfo.

Откат

Изменения локальны (две функции и одно чтение конфигурации): возврат к предыдущему коммиту; схема данных не затрагивается.