Безопасность сервиса
Содержание
Защита устроена слоями: веб-сервер (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.