Москва UTC+3
Типографская обложка на чёрном фоне: «8 найдено. 8 исправлено.», ниже четыре находки аудита tarasovvitalii.com, у каждой уровень риска и лаймовая метка «Исправлено».

Проверили изнутри безопасность этого портфолио: чат, API сообщений, сервер и 15 демо-концептов. Нашли 8 проблем, включая внедрение скрипта на домене чата, и исправили все 8.

Метки
Свой продукт Собственный продукт VITON13
Год
2026
Направления
Безопасность, Сайты
Студия
by VITON13
Языки
английский, русский, испанский, китайский

Обзор

Этот сайт — не только статичные страницы. На нём работает чат на VITON ID (Firebase Auth и Firestore), небольшой API на Node, который хранит сообщения из формы и отправляет письма, сервер nginx в Docker и копии 15 концепт-сайтов в разделе /demos/. 28 сентября 2026 года мы проверили всё это изнутри: код, правила Firestore, настройки сервера и контейнеров и npm-зависимости.

Для каждой части мы задавали вопрос злоумышленника: что с ней может сделать посторонний и чего это будет стоить владельцу? Находка засчитывалась, только если мы её воспроизвели, а каждое исправление перед выпуском перепроверяли на локальной копии рабочей конфигурации.

  • 8

    находок по безопасности, все исправлены

    Источник: Ревью кода, 28 сент. 2026

  • 1

    уязвимость высокого риска — внедрение скрипта на домене чата, закрыта

    Источник: Воспроизведено до и после исправления на локальной копии

  • 119

    демо-страниц открываются с новой политикой безопасности без нарушений

    Источник: Проверка в headless Chrome, 28 сент. 2026

  • 0

    известных уязвимостей в npm-зависимостях сайта и API

    Источник: npm audit, 28 сент. 2026

Подход

Мы прочитали каждый маршрут API, проверку токенов, правила Firestore вместе с их 39 тестами в эмуляторе, файлы nginx и Docker Compose и код всех 15 демо. Вместо атак на рабочий сервер мы подняли те же контейнеры локально (nginx и API с рабочими настройками) и пробовали каждую атаку там.

Самая серьёзная находка оказалась не на самом сайте, а в демо. Каталог Oriva вставлял параметр адреса ?cat= в страницу как HTML, поэтому специально собранная ссылка запускала скрипт на tarasovvitalii.com — на том же домене, где чат хранит сессию Firebase. Одного клика владельца хватило бы, чтобы отдать переписку. Остальные 14 демо только сравнивают параметры адреса с известными значениями.

Исправления: демо принимает только известные категории и сортировки; у /demos/ своя политика безопасности (CSP); Leaflet закреплён хэшами целостности; редирект /demos/<id> собирается по строгому шаблону; адреса, которые могли подсунуть поля в ссылки mailto:, отклоняются; общий дневной лимит защищает хранилище; API работает от непривилегированного пользователя на файловой системе только для чтения; версия nginx скрыта, а HSTS покрывает www.

Результаты

8 находок, 8 исправлено: 1 высокого уровня риска, 1 среднего и 6 низкого. Код, который срабатывал в старом демо, в новом ничего не делает, а запрос, который раньше подставлял заголовок Set-Cookie, теперь получает обычный 404. Все 119 демо-страниц открываются с новой политикой без единого нарушения, тесты API проходят 48 из 48 вместе с проверками новых правил, а npm audit не находит известных уязвимостей в зависимостях сайта и API.

Проверено и в порядке: проверка токенов Firebase (только RS256, обязательный идентификатор ключа, проверка аудитории, издателя и срока), правила Firestore (никто не читает чужую переписку и не пишет от имени владельца), шаблоны писем (все значения экранированы, подмены заголовков нет), логи (без токенов, email и IP-адресов) и интерфейс чата (текст посетителя никогда не вставляется как HTML).

Аудит безопасности

Каждую находку ниже мы сначала воспроизвели, а после исправления перепроверили на локальной копии рабочих контейнеров. Порядок — по уровню риска.

Проверено 28 сент. 2026 · находок: 8 · исправлено: 8

  1. Высокий

    Внедрение скрипта в демо-концепт на домене чата

    Исправлено

    Было

    Каталог Oriva вставлял параметр адреса ?cat= в страницу как HTML. Собранная ссылка запускала скрипт на tarasovvitalii.com, где чат хранит сессию Firebase: одного клика владельца хватило бы, чтобы открыть переписку и аккаунт владельца.

    Стало

    Принимаются только известные категории и сортировки. Тот же код больше не срабатывает, а остальные 14 демо проверены на такую же ошибку.

  2. Средний

    Демо без политики безопасности, чужой скрипт без проверки целостности

    Исправлено

    Было

    52 демо-страницы грузили Leaflet с unpkg.com без хэша целостности, а /demos/ не отдавал Content-Security-Policy: взломанный CDN или любой внедрённый скрипт получили бы доступ ко всему на домене.

    Стало

    Leaflet закреплён хэшами SRI, у /demos/ своя политика: запросы только к самому сайту, скрипты только с сайта и закреплённого файла, без плагинов. 119 страниц, 0 нарушений.

  3. Низкий

    Подмена заголовков в редиректе сервера

    Исправлено

    Было

    Редирект с /demos/<id> на /demos/<id>/ возвращал раскодированный путь как есть, поэтому %0d%0a в ссылке дописывал в ответ лишний заголовок, например Set-Cookie.

    Стало

    Редирект принимает только буквы, цифры, дефис и подчёркивание и сам собирает адрес. Тот же запрос теперь получает обычный 404.

  4. Низкий

    Скрытые поля в ссылках «Ответить» у владельца

    Исправлено

    Было

    Адрес вида me@x.com?bcc=…&body=… проходил проверку, и ссылка «Ответить» во входящих и письмах владельца подставляла скрытую копию и текст. Кроме того, в имени могли быть символы смены направления текста, которые маскируют написанное.

    Стало

    Адреса с разделителями URL отклоняются, в ссылках mailto: адрес кодируется, символы смены направления удаляются. Все три случая покрыты новыми тестами API.

  5. Низкий

    Нет общего лимита на хранение сообщений

    Исправлено

    Было

    Лимиты считались только по IP-адресу. Меняя адреса, можно было бесконечно добавлять заявки из формы и записи ботов, пока не кончится диск.

    Стало

    Поверх лимитов по IP действует общий дневной лимит на сохранение заявок (по умолчанию 500). Сверх него форма отвечает «попробуйте позже».

  6. Низкий

    API сообщений работал от root

    Исправлено

    Было

    Контейнер API работал от root, с записываемой файловой системой и всеми стандартными возможностями Linux: любая ошибка в нём дала бы злоумышленнику удобную точку опоры.

    Стало

    Он работает от непривилегированного пользователя node на файловой системе только для чтения, без возможностей Linux и без повышения привилегий.

  7. Низкий

    Версия сервера на виду, устаревшая ветка nginx

    Исправлено

    Было

    Каждый ответ содержал «server: nginx/1.27.5», а контейнер сайта использовал ветку 1.27, которая больше не получает исправлений.

    Стало

    Версия скрыта во всех ответах, а контейнер работает на актуальной стабильной ветке nginx.

  8. Низкий

    Принудительный HTTPS не охватывал www

    Исправлено

    Было

    Заголовок HSTS, который велит браузеру открывать сайт только по HTTPS, отдавался на основном домене, но не на www и не распространялся на поддомены.

    Стало

    www тоже отдаёт HSTS, а политика включает поддомены, так что http://www… тоже переводится на HTTPS.

Чего это не доказывает

Это наш собственный сайт, а не проект для клиента. Проверку провели мы сами по исходному коду; это не независимый пентест и не сертификат. Атаки мы воспроизводили на локальной копии рабочих контейнеров, а не на живом сервере.

Результат относится к тому, что мы проверили 28 сентября 2026 года: новый код, новые зависимости или новые демо требуют такой же проверки. Демо по-⁠прежнему живут на домене сайта. Новая политика ограничивает, до чего дотянется внедрённый код, а полностью изолировать демо можно, только перенеся их на отдельный домен.

Задумали что-то похожее? Каждое сообщение лично читает наш основатель — Тарасов Виталий.

Все работы

Следующий проект

Möbius School & InstituteСайт школы и вуза с личным кабинетом Концепция2026 Все работы (32)