Перейти к содержанию

Suveren: подробное руководство

Здесь всё, что не поместилось в README: что именно смотрит каждая проверка, все параметры, форматы для CI и источники данных. Список проверок с ID — в checks.md.

Содержание

Все команды

Команда Что делает
suveren scan сайт.ru полная проверка сайта
suveren batch sites.txt проверка списка сайтов: сводная таблица, CSV и отчёт по каждому
suveren company <ИНН, ОГРН или сайт> ЕГРЮЛ, санкционные списки, реестр операторов ПДн
suveren diff old.json new.json что изменилось между двумя проверками
suveren checks [ID или тег] все проверки с ID и тегами
suveren services [фильтр] база распознаваемых сервисов
suveren update скачать свежие санкционные списки и реестр блокировок
suveren doctor проверить, что все источники данных отвечают
suveren audit reports/ не противоречат ли отчёты сами себе
suveren unknown внешние домены, которых нет в базе сервисов
suveren watch sites.txt --every 24h следить за сайтами: проверять снова и сообщать, что изменилось (можно в Telegram)
suveren research sites.txt исследование: много сайтов, на выходе только сводка — доли по каждой находке, CSV и HTML с графиками; названия сайтов скрыты
suveren draft отчёт.json черновик политики или согласия по найденному (проверьте с юристом)
suveren verify сайт.ru подтвердить, что сайт ваш, — для --own-site и --form-leaks
suveren menu меню (то же, что двойной клик по exe)

Главные параметры scan (полный список — suveren scan --help):

Параметр Что делает
--browser, -b открыть сайт в браузере (Edge или Chrome): видны скрипты, которые подгружаются динамически
--profile quick\|standard\|deep quick — только иностранные сервисы; standard — все проверки (по умолчанию); deep — в браузере, до 12 страниц и с экспериментом --cutoff
--checks mail,SUV-LAW-001 только нужные проверки: по ID, префиксу или тегу
--pages N сколько внутренних страниц проверить кроме главной (по умолчанию 6)
--cutoff эксперимент: открыть сайт без иностранных сервисов и показать, что сломается
--form-leaks эксперимент: уходят ли данные из форм сторонним сервисам до отправки (только вместе с --own-site, после suveren verify)
--own-site режим «свой сайт»: .git и .env, шифры TLS, STARTTLS почты (после suveren verify)
--pdf файл.pdf сохранить отчёт ещё и в PDF
--docx файл.docx отчёт в Word: оценка, что сделать, штрафы, все проверки
--summary файл.html сводка на одну страницу для руководителя: оценка, главные риски, штрафы, что сделать
--brand-name, --brand-logo, --brand-url отчёт под брендом вашей студии
--json файл.json, --sarif файл.sarif результат для diff, CI и сканеров безопасности
--since прошлый.json что изменилось с прошлой проверки
--fail-under C, --fail-on fail ненулевой код выхода для CI
--ignore файл принятые находки с причиной, автором и сроком (по умолчанию .suveren-ignore)
--dns ru DNS-запросы только через Яндекс DNS. Остальные источники не меняются: имя сайта уходит в crt.sh, Cert Spotter и rdap.org, IP-адреса — в Team Cymru
--no-mail, --no-security, --no-subdomains, --no-152fz, --no-blocklist пропустить раздел
--dkim-selector ИМЯ свой селектор DKIM (s= в заголовке DKIM-Signature ваших писем), можно несколько раз; проверяется вместе с распространёнными
--verbose, -v печатать каждый сетевой шаг со временем (есть и у company, batch, research, doctor)

Параметры проверки

Полезные параметры scan: --pages N (сколько внутренних страниц проверить, по умолчанию 6), --details (все найденные сервисы в терминале), --quick (только иностранные сервисы, без 152-ФЗ, блокировок, почты, поддоменов и безопасности), --json file.json (сохранить для diff), --fail-under C (код выхода 3, если общая оценка хуже C, для CI), --no-open (не открывать браузер), --dns ru (DNS-запросы только через Яндекс DNS; это касается только DNS: имя сайта всё равно уходит в crt.sh, Cert Spotter и rdap.org, IP-адреса — в Team Cymru).

Отчёты сохраняются в reports/ в HTML и открываются в браузере.

Где зависает. --verbose (-v) у scan, company, batch, research и doctor печатает каждый шаг (этапы проверки, запросы DNS, HTTP, TLS, WHOIS, страницы в браузере) при начале и конце, со временем от запуска:

   7.1 с  → HTTP GET exoway.ru/
   8.7 с  ← HTTP GET exoway.ru/: код 200, 1.6 с
  12.4 с  → DNS MX exoway.ru (system)

Если сеть что-то блокирует, последней будет строка → с хостом, ответа от которого ждут. Строки идут в stderr (--json - остаётся чистым) и показывают только хост и путь: без параметров запроса, заголовков и токенов, их можно приложить к сообщению об ошибке.

Профили и выбор проверок. --profile quick — только иностранные сервисы (то же, что --quick), standard — все проверки (по умолчанию), deep — все проверки в браузере и до 12 внутренних страниц. У каждой проверки есть постоянный ID: SUV-MAIL-003 (DMARC), SUV-LAW-001 (вход через иностранные сервисы) и т. д., он показан в HTML-отчёте, JSON и SARIF. Под каждой проблемой в отчёте раскрывается «Доказательство»: на чём основан вывод, ровно так, как это увидел Suveren. Это DNS-запись (TXT _dmarc… — v=DMARC1; p=none), заголовок ответа (пустой, если его нет), адрес скрипта с уязвимой версией, форма с её полями, цитата из соглашения, запрос, в котором ушли данные из формы, запись реестра блокировок. Секреты из кода показаны замаскированными. --checks оставляет только нужные: по ID, префиксу или тегу через запятую, и запускает только те модули, которые для них нужны:

suveren checks                                  # все проверки, ID и теги
suveren scan example.ru --checks mail,headers   # только почта и заголовки безопасности
suveren scan example.ru --checks SUV-LAW-001,SUV-PD

Иностранные зависимости тоже имеют ID по категории: SUV-DEP-HOSTING, SUV-DEP-DNS, SUV-DEP-MAIL…

Описание всех проверок с ID, модулями и тегами — в checks.md.

1. Иностранные зависимости

Что Как определяется Чем грозит
DNS-серверы NS-записи и сеть их IP-адресов блокировка аккаунта кладёт сайт и почту сразу
Почта MX-записи потеря входящих писем и архива переписки
Хостинг IP сайта → сеть (ASN) и страна её владельца удаление аккаунта вместе с данными
Конструктор / CMS код страницы и сеть Tilda, Wix, Webflow, Shopify: перенести сайт непросто
CDN и анти-DDoS IP сайта недоступность и замедление для пользователей из РФ
Регистратор RDAP / WHOIS отказ в продлении домена
Доменная зона TLD санкционные требования иностранного реестра
SSL-сертификат TLS-рукопожатие отзыв сертификата иностранным УЦ
Скрипты и виджеты код главной и внутренних страниц, в режиме --browser все сетевые запросы аналитика, реклама, капча, шрифты, чаты, формы, карты, видео, оплата, вход через соцсети

Отдельно отмечаются сервисы, которые в России заблокированы или не работают: Meta (Facebook, Instagram), LinkedIn, X (Twitter), YouTube, Google Ads, а также скомпрометированный polyfill.io.

В базе около 300 сервисов, иностранных и российских (suveren services). Страной сервиса считается юрисдикция компании-владельца, а не место дата-центра: санкции применяются к компании.

Оценка. Каждая категория с иностранной зависимостью даёт один риск: высокий −20, средний −10, низкий −4. A от 90, B от 75, C от 60, D от 40, ниже — F. Если в категории есть и иностранный, и российский сервер (например, резервный NS), риск понижается на ступень. Если страницу сайта увидеть не удалось (ничего не пришло, стена от ботов или страница ошибки), скрипты и виджеты не проверены, и обе оценки не выше B: A означает «проверено и чисто», а не «ничего не увидели».

Как переехать. У каждого риска в HTML-отчёте раскрывается план: 2–5 шагов, российские варианты, сложность (легко / средне / сложно) и ориентир по стоимости — без цен в рублях, они быстро устаревают. В конце отчёта — сводный «План переезда»: сначала то, что опаснее и проще перенести. В JSON — поле migration. Данные — в src/suveren/data/migration.json.

Что сломается при отключении: эксперимент --cutoff

suveren scan example.ru --cutoff        # или --profile deep

Не прогноз, а опыт. Сайт открывается в браузере четыре раза: как обычно, без иностранных сервисов (все их запросы отклоняются, как при отключении), снова как обычно и, наконец, с зависшими иностранными сервисами: их запросы остаются без ответа, как при блокировке, которая отбрасывает пакеты. В отчёте — два скриншота рядом и что именно перестало работать: ошибки JavaScript в коде сайта (например, jQuery с Google CDN, без которого падают меню и формы), пропавшие кнопки, формы с иностранной капчей, которые не отправятся, карты и видео, картинки, шрифты, доля пропавшего текста. Отдельно — что будет при зависании: успел ли браузер хоть что-то нарисовать за 10 секунд и загрузилась ли страница до конца (обычно мешают Google Fonts или скрипты в <head>). Изменения, которых нет в обоих обычных прогонах (лента новостей, ротация баннеров, «5 минут назад»), не считаются, чтобы не было ложных тревог.

Иностранный ли хост, решает база сервисов, а для неизвестных — сеть, в которой находится его IP-адрес. Свой домен сайта не отключается: что будет при потере иностранных DNS, хостинга, CDN и почты, показывает отдельная проверка «сайт и почта целиком». Нужен Playwright (как для --browser).

Утекают ли данные из форм до отправки: эксперимент --form-leaks

suveren scan example.ru --form-leaks

Запись сессий, «ловцы брошенных заявок», рекламные пиксели с автоматическим сопоставлением читают то, что человек печатает в форме, и отправляют это ещё до нажатия «Отправить», то есть до согласия. Suveren открывает главную и до двух страниц с формами в браузере, печатает в поля имени, телефона, почты и пароля тестовые значения и ищет их во всём, что страница отправляет: открытым текстом, в base64, в сжатом виде (gzip) и как хеши MD5, SHA-1 и SHA-256. Методика — как в исследовании Leaky Forms (Senol и др., USENIX Security 2022). Проверка SUV-PD-012: пароль у стороннего сервиса или данные у иностранного — «проблема», у российского — «внимание» (152-ФЗ, ст. 7 и ст. 6 ч. 3: без согласия раскрывать данные третьим лицам и поручать им обработку нельзя).

Эксперимент трогает формы сайта, поэтому включается только своим флагом: ни профиль deep, ни --checks pd его не запускают. Формы не отправляются: событие отправки отменяется раньше обработчиков сайта. Тестовые значения никуда не дойдут: почта на example.com (RFC 2606), у телефона код 100, которого нет в плане нумерации, а номер, который маска поля превратила в другой, стирается до выхода из поля. Маски многих форм принимают только номера на 9: тогда отчёт так и говорит, что телефон не проверен, а для своего сайта можно указать свой номер — --form-phone +7XXXXXXXXXX (номера не должно быть на страницах сайта; в отчёте он скрыт). Виджет «брошенных заявок» может показать владельцу сайта тестовую заявку, поэтому запускайте эксперимент на своих сайтах или с согласия владельца. Видно то, что уходит в распознаваемом виде; зашифрованное найти нельзя, поэтому «в порядке» значит «не нашли», а не «точно нет».

2. Персональные данные и блокировки

Проверяются главная и внутренние страницы: формы чаще всего стоят в «Контактах», корзине и оформлении заказа, поэтому они проверяются в первую очередь. Одинаковая форма из шапки сайта считается один раз, а в отчёте видно, на какой странице найдена проблема.

Проверка Что смотрится
Политика обработки ПДн ссылка на главной (ст. 18.1); если ссылки нет — раздел о ПДн в пользовательском соглашении
Содержание политики 10 разделов из рекомендаций Роскомнадзора от 31.07.2017: сведения об операторе, цели, правовые основания, какие данные и чьи, действия и способы, сроки, уничтожение, права субъекта, порядок запросов, меры защиты; трансграничная передача, если на сайте есть иностранные сервисы. Если по ссылке пришла оболочка сайта без текста политики — «не проверено»
Политика и реальность сходится ли политика с сайтом: оператор с тем же ИНН, что в реквизитах, и этот сайт, а не другой (скопированная политика); все данные, которые просят формы, в перечне (ст. 18.1 ч. 1 п. 2); cookies, если на сайте счётчики и нет отдельной политики cookies; нет категоричных «не передаём третьим лицам» при сервисах, которые данные получают
Согласие в формах формы с телефоном, почтой или именем без согласия; заранее отмеченные галочки
Отдельное согласие с 1 сентября 2025 года согласие оформляется отдельно от других документов (ст. 9 ч. 1 в ред. 156-ФЗ): одна фраза «принимаю условия оферты и даю согласие на обработку» в форме или «использование сайта означает согласие на обработку» в политике и соглашении дают «внимание»; отдельный документ согласия — «в порядке»
Уведомление о cookies есть ли баннер, если на сайте аналитика, реклама или чаты
Трансграничная передача иностранные скрипты, получающие данные посетителей (ст. 12)
Хранение данных в России где физически стоит сервер сайта (база DB-IP), если на нём собираются данные (ст. 18 ч. 5); адреса CDN не в счёт
Защищённое соединение HTTPS и адреса отправки форм
Реестр операторов ПДн ИНН ищется на сайте и странице контактов, затем — в реестре Роскомнадзора
Реестр блокировок домен и IP сайта в выгрузке реестра РКН от antifilter.download (не официальный источник)
Вход через иностранные сервисы кнопки и ссылки «Войти через Google / Apple / Facebook / GitHub / Microsoft / X / Telegram» и др. (149-ФЗ, ст. 8 ч. 10; штраф по ст. 13.55 КоАП с 7 июля 2026 года)
Рекомендательные технологии блоки «Персональные рекомендации», «Вам может понравиться», «Вы недавно смотрели» и ссылка на правила их применения (149-ФЗ, ст. 10.2-2; штраф по ст. 13.56 ч. 3 КоАП с 7 июля 2026 года). Нет правил — «внимание»: снаружи не видно, строится ли подборка по интересам

Вход через иностранные сервисы. С 1 декабря 2023 года российский сайт может авторизовать пользователей из России только по номеру телефона, через Госуслуги, ЕБС или российские системы (VK ID, Яндекс ID, Сбер ID, Т-ID). Suveren смотрит главную, внутренние страницы и страницу «Войти» / «Личный кабинет»: ссылки на OAuth-адреса (accounts.google.com/o/oauth2, appleid.apple.com/auth/authorize и т. п.), собственные адреса сайта вида /auth/google, виджеты входа (Google One Tap, «Вход с Apple», Telegram Login, uLogin) и надписи на кнопках. Обычные ссылки на Google Карты, App Store, канал в Telegram или кнопка «Поделиться» входом не считаются, как и статья о том, как войти через Google. Если найден только скрипт или только надпись, без ссылки, которая начинает вход, это «внимание», а не нарушение. Иностранная почта в качестве логина требованием не запрещена.

Потенциальные штрафы. Над разделом 152-ФЗ отчёт показывает блок «Потенциальные штрафы: до N ₽»: для каждого нарушения — статья КоАП и вилка для юрлица, ИП, должностного лица и при повторном нарушении, если закон его выделяет. В сумму входят только безусловные штрафы за найденные проблемы, по одной статье на нарушение: сейчас это «нет политики» (ст. 13.11 ч. 3). Если квалификация зависит от обстоятельств, которых Suveren не видит, штраф показан с условием, но в сумму не входит: база за рубежом (ч. 8, «если заявки с сайта хранятся на этом сервере»), вход через иностранные сервисы (ст. 13.55, «если владелец сайта — российская компания или гражданин»). Предупреждения «форма без согласия» (ч. 1, «если для этой обработки нужно согласие»: для заявки на договор или обращения в госорган оно не нужно) и «нет в реестре операторов» (ч. 10) показываются, но в сумму не входят. «Не проверено» в расчёт не попадает. Суммы сверены с текстом КоАП на consultant.ru (ред. от 04.08.2026). Это оценка максимального риска, а не юридическое заключение. В терминале — одна строка с итогом, в JSON — поле fines.

Крупные сайты часто отдают роботам пустую страницу или проверку «вы не робот». Suveren это распознаёт и честно пишет «не проверено» вместо ложной ошибки, а режим --browser в большинстве таких случаев получает настоящую страницу.

3. Защита почты от подделки

Фишинг и поддельные счета чаще всего приходят «от директора» или «от бухгалтерии» настоящего домена компании. Suveren читает DNS-записи домена, как это делает почтовый сервер получателя, и отвечает простым языком: можно ли подделать письмо от имени @ваш-домен — да, частично или нет, и что исправить.

Проверка Что смотрится
Вердикт DMARC с политикой reject — нет; quarantine или pct < 100 — частично (письма уйдут в спам); p=none или нет DMARC — да. Отдельно отмечается sp=none, при котором не защищены поддомены
SPF одна ли запись, +all / ?all, лимит в 10 DNS-запросов по всей цепочке include и redirect. Если DNS не ответил на include или redirect, запрос повторяется один раз, и только потом проверка говорит, что цепочку проверить не удалось
DMARC политика, pct, адрес для отчётов rua
DKIM ключи по распространённым селекторам (Яндекс 360, VK WorkSpace, Microsoft 365, Google, рассыльщики) и по вашим (--dkim-selector); если не найдены — «не проверено», а не ошибка. Список ключей домена снаружи не получить: свой селектор видно в заголовке DKIM-Signature (s=) любого письма
MTA-STS, TLS-RPT шифрование входящей почты
BIMI для сведения: есть ли запись default._bimi с логотипом и покажут ли его (нужен DMARC quarantine или reject для всех писем, а Gmail и Apple Mail ещё требуют сертификат VMC или CMC). Никогда не «внимание»: на защиту от подделки BIMI не влияет; если DNS не ответил, проверки нет

Домену, который не принимает почту, тоже нужна защита: Suveren подскажет записи v=spf1 -all и p=reject. Проверка только читает DNS и публичный файл политики MTA-STS, писем не отправляет. Отключить её можно параметром --no-mail.

4. Поддомены и их захват

Каждый публичный SSL-сертификат попадает в журналы Certificate Transparency, поэтому список поддоменов компании виден любому, включая давно забытые промо-сайты. Если такой поддомен по-прежнему ведёт (CNAME) на сервис, где проект уже удалён, его может подключить к себе другой клиент сервиса и показывать на настоящем домене компании свою страницу: фишинг, кража cookies.

Признак Как определяется
CNAME ведёт на свободный домен домена нет в DNS, и реестр (RDAP, для .ru/.рф — WHOIS) подтверждает, что он не зарегистрирован. Если реестр не ответил — только предупреждение
Ресурс в облаке удалён CNAME на Azure, Elastic Beanstalk и т. п., а имя больше не существует
Сервис отвечает «такого проекта нет» страница-заглушка GitHub Pages, Heroku, Netlify, AWS S3, Yandex Object Storage, Shopify, Read the Docs и ещё 32 сервиса

Сигнатуры взяты из открытого справочника can-i-take-over-xyz (CC BY 4.0); тексты заглушек для 13 сервисов сверены вживую. Каждая находка подаётся как «возможный захват, проверьте вручную». Поддомены берутся из crt.sh (запасной источник — Cert Spotter, результат кэшируется на сутки), проверяются первые 300. Имя домена при этом уходит в эти сервисы; отключить проверку можно параметром --no-subdomains. Список поддоменов к сайту не обращается, а проверка захвата прощупывает: DNS и по одному запросу к страницам поддоменов, которые ведут на известный сервис.

5. Безопасность сайта

Проверка Что смотрится
Сторонний код с каких чужих адресов страницы загружают скрипты: каждый из них может выполнить на сайте любой код
Брошенные и скомпрометированные домены домен скрипта не зарегистрирован (подтверждается через RDAP/WHOIS) — его может купить кто угодно; домены, раздававшие вредоносный код в 2024 году (polyfill.io и связанные с ним)
Ключи и секреты в коде собственные скрипты сайта и скрипты внутри страниц: приватные ключи, токены Telegram-ботов, ключи AWS, Stripe, GitHub, Slack, SendGrid, OpenAI, Anthropic, OAuth-токены Яндекса и ключи Yandex Cloud — «проблема»; ключ Google API, публичный по задумке, — «внимание», его нужно ограничить по домену. Значения в отчёте замаскированы (AKIA…4D)
Уязвимые версии библиотек jQuery, jQuery UI, Bootstrap, lodash, Moment.js, AngularJS, Vue.js, React — только если версия написана явно (в имени файла, пути CDN или в заголовке самой библиотеки). Версия сверяется с базой retire.js: она скачивается раз в сутки, а без сети берётся встроенная копия (src/suveren/data/retire.json); какая копия и от какого числа — в доказательствах. Неподдерживаемые ветки (jQuery 1–2, Bootstrap 3, AngularJS 1.x) отмечаются отдельно; уязвимости, которые бывают только на сервере (в том числе при отрисовке React и Vue на сервере), не учитываются. Статус — «внимание»: можно ли воспользоваться уязвимостью, зависит от того, как сайт вызывает библиотеку
Версия CMS WordPress и 1С-Битрикс по тегу generator и путям их файлов (/wp-content/, /bitrix/) на уже загруженных страницах, без лишних запросов к сайту. Версия показывается, если видна (у WordPress — по тегу generator или по своим файлам вроде wp-emoji-release.min.js?ver=), но статус всегда «не ясно»: открытой базы уязвимостей по версиям этих CMS без ключа API нет, и Suveren не гадает. В совете — где проверить обновления
Цепочки сторонних скриптов в режиме --browser: кто какой скрипт подключил (по данным браузера). Код, который подключил не сайт, а чужой скрипт (тег-менеджер, рекламная сеть), — «внимание»; в HTML-отчёте — схема цепочек
SRI атрибут integrity у библиотек с публичных CDN (cdnjs, jsDelivr, unpkg и др.). Скрипты аналитики и виджетов меняются постоянно, у них SRI быть не может, и Suveren его не требует
CSP есть ли политика, нет ли в ней 'unsafe-inline' без nonce, 'unsafe-eval', разрешения скриптов отовсюду, запрещены ли плагины (object-src 'none' или строгий default-src)
HSTS заголовок и срок не меньше 180 дней
Защитные заголовки защита от встраивания в чужие страницы (X-Frame-Options или frame-ancestors) и X-Content-Type-Options: nosniff
Permissions-Policy какие функции браузера (камера, микрофон, геолокация, оплата) разрешены странице и встроенным в неё чужим фреймам. Заголовка нет — мягкое «внимание» (совет OWASP Secure Headers, срочность низкая); заголовок в синтаксисе старого Feature-Policy (camera 'none') браузер отбрасывает целиком — тоже «внимание»
Cookies флаги Secure, HttpOnly и SameSite у cookies, похожих на сессионные (CSRF-токены не трогаются: их должны читать скрипты)
TLS срок сертификата и не принимает ли сервер устаревшие TLS 1.0 и 1.1

Сценарии атак. Отчёт открывается разделом, где находки из разных модулей собраны в то, что сделал бы злоумышленник: «фишинг от имени компании» (почту можно подделать + на сайте есть формы или оплата), «чужой код у всех посетителей» (брошенный домен скрипта или CDN без SRI и CSP), «захват поддомена», «перехват при первом заходе» (нет HSTS + формы), «утёкший ключ», «отключение сайта и почты». Сценарий появляется, только если найдена вся цепочка; каждый шаг ссылается на ID проверки, а совет называет одно действие, которое цепочку рвёт.

Если вместо сайта ответила защита от ботов или сайт перенаправил на другой домен, заголовки не оцениваются: у заглушки они свои. TLS проверяется у того адреса, который вы указали, а не у сервера, куда ведёт перенаправление. Отключить раздел можно параметром --no-security.

6. Проверка компании

suveren company 7707083893      # по ИНН
suveren company 1027700132195   # по ОГРН
suveren company example.ru      # ИНН будет найден на сайте
  • ЕГРЮЛ / ЕГРИП (ФНС): название, статус, дата регистрации, руководитель. Ликвидированная или слишком молодая компания отмечается.
  • Санкционные списки США (OFAC SDN), ЕС и Великобритании. Совпадение по ИНН/ОГРН точное; совпадение по названию учитывает транслитерацию («СБЕРБАНК РОССИИ» = «Sberbank of Russia»). Руководитель проверяется по фамилии и имени, такие совпадения помечаются как возможные.
  • Реестр операторов ПДн Роскомнадзора.
  • Сверка с сайтом: указан ли ИНН на сайте и совпадает ли владелец домена в WHOIS.

Списки (около 110 МБ) скачиваются при первой проверке и обновляются раз в сутки. Кэш хранится в %LOCALAPPDATA%\suveren\cache на Windows и в ~/.cache/suveren на Linux и macOS.

PDF и отчёты под брендом студии

suveren scan example.ru --pdf example.pdf --brand-name "Студия Север" --brand-logo logo.png --brand-url sever.ru
suveren company 7707083893 --pdf company.pdf --brand-name "Студия Север"

--pdf печатает отчёт в PDF (A4) тем же браузером, что и --browser (нужен Playwright), блоки «Как переехать» в нём раскрыты. --brand-name, --brand-logo (PNG, JPEG или SVG до 512 КБ, встраивается в отчёт) и --brand-url ставят в шапку и подвал вашу студию вместо Suveren; строка «Сделано с помощью Suveren» остаётся. Работает в scan, batch и company. Чтобы не повторять параметры, задайте переменные окружения SUVEREN_BRAND_NAME, SUVEREN_BRAND_LOGO, SUVEREN_BRAND_URL.

Массовая проверка

Для веб-студий и аудита нескольких сайтов: файл со списком, по одному домену в строке.

suveren batch sites.txt --browser

В папке reports/batch-… появятся index.html со сводной таблицей, summary.csv для Excel и отчёт по каждому сайту. Сайты идут от худшей общей оценки к лучшей, независимость — в соседней колонке. В summary.csv прежние колонки grade и score по-прежнему означают независимость, общая оценка добавлена в конец: overall_grade и overall_score. Сайты, которые проверить не удалось, тоже есть в таблице: причина — в последней колонке error.

Исследование по многим сайтам

suveren research sites.txt проверяет список сайтов (можно сотни) и собирает только сводку: какая доля сайтов с каждой находкой, а если в списке указан тип сайта — то и по типам. Сайты проверяются параллельно (по умолчанию по 4); прерванный прогон продолжается с того же места. Сырые отчёты лежат в reports/research/raw/, сводка — в summary.csv и summary.html с графиками, без внешних скриптов. «Не проверено» в доли не входит. Названия сайтов в сводке скрыты; --show-domains показывает их — только для себя, такой список не публикуют.

shop.ru, магазин
clinic.ru, медицина

Слежение за сайтами

suveren watch sites.txt проверяет сайты из списка снова и сравнивает с прошлым разом: какие сервисы появились или пропали, какие проверки стали лучше или хуже. Изменения пишутся в reports/watch/changes.log. Если изменений нет, ничего не приходит.

Чтобы изменения приходили в Telegram, создайте бота у @BotFather и задайте его токен и чат (токен не попадает ни в отчёты, ни в журнал):

suveren watch sites.txt --once --telegram-token 123456:ABC... --telegram-chat 123456789
# или через переменные окружения (так токена нет в истории команд):
setx SUVEREN_TELEGRAM_TOKEN "123456:ABC..."
setx SUVEREN_TELEGRAM_CHAT "123456789"

Каждый день в 9:00 через Планировщик заданий Windows (один круг за запуск):

schtasks /Create /SC DAILY /ST 09:00 /TN "Suveren watch" ^
  /TR "\"C:\Suveren\Suveren.exe\" watch C:\Suveren\sites.txt --once --state C:\Suveren\watch"

Или вручную: Планировщик заданий → «Создать простую задачу» → «Ежедневно» → «Запустить программу»: программа C:\Suveren\Suveren.exe, аргументы watch C:\Suveren\sites.txt --once --state C:\Suveren\watch. В меню (Suveren.exe или Suveren.bat) это пункт 9 «Следить за сайтами».

Отслеживание импортозамещения

suveren scan example.ru --json before.json
# ... переехали на российские сервисы ...
suveren scan example.ru --json after.json
suveren diff before.json after.json
example.ru: независимость D → A, 52 → 96 из 100

  − убран    DNS-серверы: Cloudflare
  − убран    Почта: Google Workspace
  + добавлен DNS-серверы: Selectel
  + добавлен Почта: Яндекс 360
  ✓ Уведомление о cookies: warn → ok

CI и другие инструменты

suveren scan example.ru --no-open --sarif suveren.sarif --fail-on fail
  • --sarif файл — результат в SARIF 2.1.0, стандартном формате сканеров безопасности: его читают GitHub и GitLab code scanning, DefectDojo и другие системы. В файл попадают проблемы (error), «внимание» (warning), «не проверено» и иностранные зависимости низкого риска (note); пройденные проверки — нет. Оценки лежат в runs[0].properties: общая (overallGrade, overallScore, overallIncomplete — почему неполная) и независимость от иностранных сервисов (grade, score).
  • --json - или --sarif - выводят результат в stdout, а всё остальное — в stderr: suveren scan example.ru --json - --no-report | jq .overall_grade. Ошибки всегда идут в stderr.
  • --json файл — полный результат, в том числе пройденные проверки (нужен для diff). Формат описан JSON-схемой src/suveren/data/report.schema.json; поле schema_version растёт по semver, проверки различайте по id (SUV-…), а не по названию. С версии схемы 1.4 у каждой проверки есть evidence: список {kind, what, value} (тот же список — в properties.evidence результата SARIF).
  • --since прошлый.json — раздел «С прошлой проверки»: какие сервисы убраны или добавлены и какие проверки стали лучше или хуже (то же сравнение, что в suveren diff).
  • --plugin файл.py — свои проверки, см. plugins.md.
  • --ignore файл — принятые находки (по умолчанию .suveren-ignore в текущей папке, если он есть; работает и в batch). Одна строка — одно исключение: ID проверки, сайт (домен, его поддомены тоже подходят, или * — любой), последний день действия, автор одним словом и причина до конца строки. Строки с # пропускаются:
# ID          сайт         до          автор    причина
SUV-MAIL-005  example.ru   2027-01-31  ivanov   MTA-STS настроим после переезда почты
SUV-WEB-004   *            2026-12-31  petrova  CSP готовим в задаче WEB-123

Принятая проблема остаётся в отчёте со своим статусом и пометкой «Принято до … (автор): причина», но не входит в «Что сделать», общую оценку, --fail-on и --fail-under. В JSON у неё есть accepted (схема 1.9), в SARIF — suppressions со статусом accepted, и code scanning показывает её закрытой. Принять можно только «проблему» или «внимание»: «не проверено» ничего не скрывает. Возможный штраф за принятую проблему остаётся в расчёте: закону решение команды не важно. После срока исключение перестаёт действовать, и в замечаниях отчёта написано, какое истекло. Исключение для проверки, которая уже в порядке, тоже названо: его можно удалить. Файл с ошибкой (нет причины, дата не ГГГГ-ММ-ДД, неизвестный ID) не читается целиком, и проверка не начинается.

Коды выхода:

Код Когда
0 проверка прошла
1 проверка не выполнена (сайт не найден, сеть); batch — хотя бы один сайт не проверен или строка списка пропущена (отчёты по остальным всё равно записаны)
2 неверные параметры
3 --fail-under C: общая оценка хуже C
4 --fail-on fail: есть проверки со статусом «проблема»; --fail-on warn — ещё и «внимание»
5 suveren audit: в отчётах есть противоречия
6 задан --fail-under или --fail-on, пороги не нарушены, но оценка неполная (стена от ботов, не ответил реестр или журнал сертификатов): то, чего не видно, порог не проверяет. --allow-incomplete принимает неполную оценку

В batch пороги --fail-under и --fail-on действуют по худшему сайту, код 1 (сайт не проверен) важнее кодов 3, 4 и 6. --timeout — таймаут одного сетевого запроса, --max-time — предел на всю проверку сайта (у scan по умолчанию 600 с, у batch — 300 с на сайт); не уложилась — код 1 у scan, «не проверен» у сайта в batch. В CI (переменная CI) и при выводе не в терминал отчёт в браузере не открывается. В summary.csv колонка grade — оценка независимости от иностранных сервисов, общая оценка — overall_grade.

Режим --browser

Обычная проверка читает HTML главной страницы. Современные сайты часто собирают страницу скриптами, а аналитику подключают через менеджеры тегов, и в исходном HTML этого не видно. С --browser Suveren открывает сайт в настоящем браузере (Edge или Chrome, которые уже стоят в системе) и учитывает все сетевые запросы страницы.

Нужен пакет Playwright: pip install playwright (уже входит в suveren[browser] и ставится Suveren.bat). Если в системе нет ни Edge, ни Chrome: playwright install chromium.

Источники данных

Данные Источник
DNS системный резолвер; если он отвечает неполно — Яндекс DNS по DNS-over-TLS, и только если не ответил и он — DNS-over-HTTPS Google и Cloudflare (об этом пишется в отчёте)
Сети и страны IP-адресов Team Cymru IP-to-ASN (через DNS)
Регистратор RDAP, WHOIS реестров
ЕГРЮЛ / ЕГРИП egrul.nalog.ru (ФНС России)
Операторы ПДн pd.rkn.gov.ru (Роскомнадзор)
Реестр блокировок выгрузка реестра РКН от antifilter.download
Поддомены журналы Certificate Transparency: crt.sh, запасной — Cert Spotter
Санкции OFAC SDN (США), сводный список ЕС, UK Sanctions List
Уязвимые библиотеки база retire.js (раз в сутки; без сети — встроенная копия с датой)
Адреса облаков списки AWS, Google Cloud, Oracle Cloud, DigitalOcean (раз в неделю)

Все источники открытые и бесплатные, ключи API не нужны. Государственные сайты иногда меняются без предупреждения, поэтому suveren doctor проверяет каждый источник, а на GitHub эта проверка запускается ежедневно.

Ограничения

  • Кроме главной проверяются до 6 внутренних страниц (--pages): в первую очередь «Контакты», заявки, корзина, доставка, услуги. Сервисы, которые есть только на остальных страницах, могут не попасть в отчёт.
  • Часть сайтов блокирует даже браузерный режим: тогда проверки по коду страницы помечаются как «не проверено».
  • Если сайт за CDN, настоящий хостинг скрыт, и Suveren об этом предупреждает.
  • Совпадения по названию и ФИО в санкционных списках нужно проверять вручную.
  • Suveren в основном смотрит: публичные DNS-записи, WHOIS, открытые реестры и обычная загрузка страниц. Прощупывает он в двух местах (соединения по TLS 1.0 и 1.1, страницы поддоменов), а --form-leaks вводит тестовые данные в формы. Метки каждой проверки — в checks.md и в разделе README «Что Suveren делает с сайтом». Никакого сканирования портов и подбора.
  • Отчёт помогает расставить приоритеты и не является юридическим заключением. У каждой проверки 152-ФЗ указано основание (статья закона) со ссылкой на текст, чтобы вывод можно было перепроверить.

Как добавить сервис в базу

База — это файл данных src/suveren/data/services.json, программировать не нужно. Инфраструктура (DNS, почта, хостинг) лежит в разделе infra:

{
 "name": "Hetzner",
 "country": "DE",
 "ns": ["hetzner.com"],
 "mx": ["your-server.de"],
 "asn": [24940],
 "as_names": ["hetzner"]
}

country — страна компании (ISO 3166), ns и mx — суффиксы серверов, asn — номера автономных систем, as_names — фрагменты названия сети. Сервисы, подключаемые на странице, лежат в разделе page: у них есть категория и регулярные выражения по коду страницы:

{"name": "Яндекс Метрика", "country": "RU", "category": "analytics", "page": ["mc\\.yandex\\.(?:ru|com)"]}

Тест test_data_file_entries_are_valid проверит, что запись корректна. Добавьте тест в tests/test_services.py и откройте pull request. Если не хотите ничего править, откройте issue «Добавить сервис»: там простая форма. Подсказка, что добавлять: suveren unknown показывает домены, которые встречались при проверках, но которых нет в базе (список хранится только на вашем компьютере).

Разработка

pip install -e ".[dev,browser]"
pytest
ruff check . && ruff format --check .

Тесты не ходят в сеть: ответы реестров и фрагменты санкционных списков лежат в tests/fixtures.

Проверка на случайных данных. tests/test_fuzz.py гоняет разборщики SPF (вместе с обходом include и redirect), DMARC, MTA-STS, CSP, Set-Cookie и карты сайта на мусоре: настоящий синтаксис вперемешку со случайным текстом, кавычками, управляющими символами и битым UTF-8 (Hypothesis). Разборщик должен ответить, а не упасть. В обычном прогоне 200 примеров на разборщик, каждый раз одни и те же; для долгой охоты:

SUVEREN_FUZZ=20000 pytest tests/test_fuzz.py

Найденный пример Hypothesis сокращает до минимального и печатает. Его стоит сохранить отдельным тестом рядом с исправлением, как test_a_broken_sitemap_line_in_robots_does_not_crash_the_scan.

Эталонный корпус. Проверки по страницам (152-ФЗ, согласие, вход через иностранные сервисы) ошибаются на реальной вёрстке, которой нет в fixtures. Поэтому реальные сайты можно записать один раз, байт в байт, и прогонять на них каждую правку офлайн:

python tests/golden.py record habr.com drom.ru   # записать сайты в corpus/
pytest tests/test_corpus.py                      # упадёт и покажет разницу, если выводы изменились
python tests/golden.py update                    # принять новые выводы, если так и задумано

Корпус хранится только локально (corpus/ в .gitignore): это чужие страницы. Без него тест пропускается.