▤ Руководства

Безопасность сервиса

Содержание

Защита устроена слоями: веб-сервер (nginx) → первый рубеж приложения (src/Security/Gate, InputGuard) → маршруты (CSRF, права, лимиты) → исходящие запросы (Http, Egress, Deny). Каждый слой работает сам по себе.

Ввод пользователя

  • До маршрутов InputGuard проверяет адрес запроса (до 4096 знаков), cookie (до 8 КБ), тело (до 1,5 МБ; для загрузки файлов — до post_max_size), число параметров (до 1000), вложенность (до 3), длину имени параметра (до 100).
  • Предел длины значения зависит от имени поля: адреса url/domain/host/… — 2048, домен в поиске d — 500, e-mail — 320, пароль — 1024, остальные — 2000. Длинные поля (text, urls, hosts, csv и т. п.) перечислены в InputGuard::LONG; для /tools/… и /admin… предел задаёт сам раздел.
  • Нулевые байты, управляющие символы в адресе и неверная UTF-8 отклоняются. В однострочных полях отклоняется явная разметка исполняемого кода (<script>, <iframe>, onerror=…(, javascript:, data:text/html); в редакторах текста и кода она допустима как данные и всегда экранируется при выводе.
  • Все текстовые поля и textarea получают maxlength, равный серверному пределу (Security\Forms). Серверная проверка обязательна, maxlength — лишь подсказка браузеру.
  • Ссылки javascript:, vbscript:, data:text/html в href/src/action на выходе заменяются на #. Дополнительно действует CSP без unsafe-inline для скриптов.
  • Заголовок Host проверяется; при заданном base_url он заменяется каноническим, поэтому ссылки в письмах и редиректы не строятся из чужого значения. Задайте SEOMASTER_BASE_URL.

Вредоносные и «подсунутые» сайты

  • Сервис только читает чужие страницы как текст и данные: страницы не исполняются, браузера внутри нет. Размер ответа ограничен (по умолчанию 2 МБ, жёсткий предел 12 МБ), заголовков — 128 КБ; медленные «капельные» ответы обрываются.
  • Разрешены только протоколы HTTP и HTTPS (в том числе при редиректах), порты 80/443/8080/8443, не более 8 редиректов. Адрес каждого шага проверяется: закрытые сети, IPv6 со спрятанным IPv4 (NAT64, 6to4, Teredo), multicast, link-local; DNS закрепляется на проверенных адресах (защита от подмены DNS).
  • Сжатые sitemap и ответы распаковываются с пределом 20 МБ (Util::gunzip): «gzip-бомба» не исчерпывает память.
  • Картинки и HEIC из недоверенных источников обрабатываются ImageMagick с явным форматом входа и лимитами памяти и времени.
  • Запретный список (Security\Deny): домены из SEOMASTER_DENY_HOSTS (через запятую) и файла storage/deny-hosts.txt. Управление: php bin/deny.php list|add|remove|check. Запись example.com закрывает и поддомены, *.example.com — только поддомены.
  • База угроз: при заданном ключе Google Web Risk (или Safe Browsing) домен проверяется до обращения к нему; заражённые и фишинговые домены не проверяются, пользователь видит причину. Ответ кэшируется на 6 часов. Без ключа этот слой выключен.

Защита от использования сервиса в DDoS

  • Общий лимит обращений к одному чужому хосту: 240 в минуту со всего сервиса и 90 в минуту от одного посетителя (SEOMASTER_EGRESS_HOST_MINUTE); за один запрос страницы — не более 250 исходящих обращений (SEOMASTER_EGRESS_PER_REQUEST).
  • Фоновые процессы (очередь, обходы, мониторинг) не отклоняются, а выдерживают паузу не менее 50 мс между обращениями к одному хосту (около 20 в секунду); одновременно к одному хосту — не более 6 соединений.
  • Проверка портов: только список разрешённых портов, не более 6 за раз, лимит на адрес и на посетителя, только публичные адреса, учёт в Egress.
  • Подтверждение владения (v142): регулярные проверки — расписание, мониторинг, доступность, отслеживание страниц — создаются только для сайтов, владение которыми подтверждено на странице /verify одним из способов: файл /.well-known/seomaster-verify.txt с кодом, метатег seomaster-verify на главной или TXT-запись seomaster-verify=код. Подтверждение домена действует на поддомены, администратор освобождён. Это проверяется и в маршрутах, и в хранилище (запасной рубеж, закрывает API и мастер первого запуска). Отключение: SEOMASTER_REQUIRE_OWNERSHIP=0. Ранее созданные проверки продолжают работать.
  • Лимиты запросов по адресу посетителя (rate_limit), CAPTCHA для анонимов, общий предел POST (90 в минуту с адреса), «штрафы»: 8 недопустимых запросов за 10 минут закрывают адрес на 10 минут.
  • Веб-сервер: limit_req (15 запросов в секунду на адрес, POST — 2 в секунду), limit_conn (30 соединений), таймауты заголовков и тела (защита от slowloris), малые буферы заголовков. Конфигурация — deploy/nginx.conf. За CDN или балансировщиком настройте реальный адрес клиента.

Заголовки и PHP

  • Всегда: CSP, X-Content-Type-Options, X-Frame-Options, Referrer-Policy, Permissions-Policy, Cross-Origin-Opener-Policy; по HTTPS ещё Strict-Transport-Security.
  • deploy/php.ini: max_input_vars, max_input_time, allow_url_fopen = Off, allow_url_include = Off, строгий режим сессий, ограничение обратного хода регулярных выражений.

Чего это не делает

  • Не заменяет защиту сети: объёмные атаки на канал останавливаются у провайдера или CDN, а не в приложении.
  • Не проверяет файлы на вирусы антивирусом: загружаемые файлы только разбираются как CSV/текст/изображения и не исполняются.
  • Без ключа Web Risk сервис не знает, что чужой домен заражён; ему поможет запретный список.
  • Разовую проверку чужого сайта может запустить любой посетитель в пределах лимитов; общий лимит на хост и паузы защищают чужой сайт от перегрузки, но не заменяют подтверждение владения сайтом; оно требуется только для регулярных проверок, а разовые проверки доступны всем в пределах лимитов.

Версия 149: проверка адреса выполняется до соединения внутри Http (в том числе для IP в URL), редиректы cURL выключены и обрабатываются вручную; ссылки в письмах строятся из base_url, а не из заголовка Host; закрытый режим действует на сеансы, API-ключи и MCP.