Files
ipwhitelist-app/research/opus-review-validators.md
T

3.6 KiB
Raw Blame History

Ответ Claude Opus 4 — код-ревью validators.js

Дата: 2026-05-30

🔴 Баг 1 — запрещённые диапазоны обходятся бо́льшей подсетью (критично)

Проверка блокировки использует isSubnetOf(normalized, blocked) — то есть «запись внутри запрещённого диапазона». Но не проверяется обратное направление: запись, которая САМА содержит запрещённый диапазон.

Поскольку ТЗ разрешает маски вплоть до /22, а многие запрещённые блоки — это /24, их можно обойти суперсетью:

Вход: 192.0.2.0/22
→ нормализуется в 192.0.0.0/22  (диапазон 192.0.0.0  192.0.3.255)

Этот /22 содержит TEST-NET-1 (192.0.2.0/24) и IANA special (192.0.0.0/24), но isSubnetOf вернёт false (родитель не внутри ребёнка) → запись пройдёт валидацию. То же с 198.18.0.0/15 (Benchmarking) и др.

Фикс — использовать пересечение вместо вложенности:

  for (const blocked of BLOCKED_RANGES) {
    if (overlaps(normalized, blocked)) {
      throw new Error(`Диапазон ${normalized} пересекается с запрещённым (${blocked})`);
    }
  }

overlaps ловит оба направления (и когда запись внутри блока, и когда блок внутри записи). isSubnetOf после этого фикса в блокировке не нужен.


🟡 Замечание 2 — parseInt глотает мусор в маске

const mask = parseInt(maskStr, 10);

10.0.0.0/24abcparseInt('24abc') = 24, запись принимается как /24. Строгая проверка:

  if (!/^\d{1,2}$/.test(maskStr)) throw new Error('Некорректная маска');
  const mask = parseInt(maskStr, 10);

🟡 Замечание 3 — множественные слэши не отсекаются

10.0.0.0/24/8.split('/') → ['10.0.0.0','24','8'], третий элемент молча игнорируется. Добавить проверку числа частей:

  const parts = cidr.split('/');
  if (parts.length !== 2) throw new Error('Некорректный формат CIDR');
  const [addr, maskStr] = parts;

🟢 Не баги (проверено)

  • overlaps — формула a.start <= b.end && b.start <= a.start || b.start <= a.end && a.start <= b.start хоть и обфусцирована, математически эквивалентна стандартной a.start <= b.end && b.start <= a.end. Работает корректно. Можно упростить для читаемости, но это не дефект.
  • Битовая арифметика с <<8 уходит в знаковый 32-бит, но финальный >>> 0 всё исправляет. Корректно.
  • Маска /0, 1 << (32-mask) — безопасно, т.к. mask ограничен 2232.

Итог: один настоящий эксплуатируемый баг (#1 — обход TEST-NET/special через /22), два мелких по строгости парсинга. Главное — поправить блокировку на overlaps.