Безопасность веб-сайта для новичка: секреты, доступы, формы и резервные копии

Безопасность сайта для новичка начинается не со сложного сканера. Сначала нужно убрать несколько частых рисков: ключи в браузере, общий пароль администратора, доверие к данным формы, отсутствие обновлений и резервная копия, которую никто не восстанавливал.

Ни один чек-лист не гарантирует защиту. Но эти шаги уменьшают поверхность атаки и помогают быстрее заметить проблему.

Составьте карту сайта

Запишите части системы:

· публичные страницы;

· форма заявки;

· личный кабинет;

· административная панель;

· серверное API;

· база данных;

· файловое хранилище;

· внешние сервисы;

· домен и DNS;

· CI/CD и хостинг.

Для каждой части укажите владельца, способ входа и данные. Карта из десяти строк полезнее общего обещания «все защищено».

Отдельно отметьте production, test и локальную среду. Один и тот же ключ во всех трех средах связывает эксперимент с рабочими данными.

Уберите секреты из кода

Ключ API, пароль базы, токен бота и секрет платежного webhook не должны находиться в Git или клиентской сборке.

Локально используйте переменные окружения и .env, добавленный в .gitignore. В production храните значения в настройках платформы или менеджере секретов.

Проверьте:

git status git diff --cached

Не добавляйте все файлы одной командой, пока не прочитали список.

Если секрет уже попал в репозиторий, удаление строки не решает проблему. История могла быть скопирована, а значение увидел внешний сервис. Сначала отзовите credential у провайдера, создайте новый и обновите разрешенные среды.

Не используйте один ключ для сайта, CI и личного ноутбука. Разделение позволяет отозвать один доступ без остановки всей системы.

Не храните закрытый ключ в браузере

Все, что отправлено пользователю в HTML или JavaScript, можно прочитать. Обфускация и «секретное» имя переменной не защищают значение.

Браузер обращается к вашему серверу, а сервер добавляет закрытый ключ и вызывает внешнюю систему. Публичный идентификатор проекта можно держать в клиенте только если провайдер так задумал и безопасность обеспечивается серверными правилами.

Проверьте production bundle поиском известных префиксов ключей. Не выводите окружение целиком в диагностическую страницу.

Настройте индивидуальные доступы

У каждого администратора должна быть своя учетная запись. Общий логин не позволяет понять, кто изменил данные, и усложняет отзыв доступа.

Включите двухфакторную аутентификацию для:

· регистратора домена;

· DNS;

· GitHub;

· хостинга;

· базы;

· почтового и платежного сервиса;

· административной панели.

Выдавайте минимальную роль. Человеку, который редактирует тексты, не нужен доступ к billing и ключам.

Раз в квартал и после ухода сотрудника проверяйте участников, токены, SSH-ключи и приложения OAuth. Удаление пользователя из одного сервиса не отзывает его доступ в остальных.

Защитите административную панель

Не считайте случайный URL защитой. Сервер должен проверять авторизацию и роль для каждого административного запроса.

Протестируйте прямой вызов API без входа и от имени обычного пользователя. Спрятанная кнопка не мешает отправить запрос вручную.

Ограничьте число попыток входа и настройте безопасное восстановление пароля. Не сообщайте публично, существует ли конкретный email, если это не требуется сценарием.

Записывайте значимые действия: вход, изменение роли, экспорт, удаление и настройку интеграции. Журнал защищайте от редактирования обычным администратором и не складывайте туда пароли.

Проверяйте форму на сервере

Ограничения HTML улучшают интерфейс, но пользователь может обойти их. Сервер заново проверяет каждое поле.

Определите:

· обязательность;

· тип и максимальную длину;

· допустимый формат;

· разрешенные значения справочника;

· размер и тип файла;

· связь объекта с текущим пользователем.

Не собирайте SQL или команду оболочки конкатенацией пользовательской строки. Используйте параметризованные запросы и безопасные API библиотек.

Экранируйте вывод по контексту. Текст пользователя, вставленный в HTML без обработки, может стать выполняемым скриптом.

Ограничьте спам и повторы

Публичная форма быстро получает автоматические запросы. Добавьте rate limit по подходящему признаку, защиту от ботов и наблюдение за всплесками.

Не полагайтесь только на CAPTCHA. Сервер должен ограничивать ресурсы и проверять содержимое независимо.

Для создания заявки используйте защиту от двойной отправки. Пользователь может нажать кнопку повторно или сеть повторит запрос.

Показывайте успех только после того, как сервер сохранил заявку. Если отправка письма сломалась, запись не должна исчезнуть. Уведомление повторяется отдельно.

Работайте с файлами осторожно

Не доверяйте расширению и заголовку браузера. Ограничьте размер, допустимые типы и число файлов. Генерируйте серверное имя вместо использования исходного пути.

Храните пользовательские файлы вне исполняемого каталога приложения. Для закрытых документов используйте проверку доступа или короткоживущую ссылку.

Не позволяйте загрузить HTML или скрипт и затем открыть его с доверенного домена без безопасной обработки.

Проверьте удаление: удаление записи из базы не всегда удаляет объект в storage, и наоборот.

Включите HTTPS

Весь production-трафик должен идти по HTTPS. HTTP перенаправляется на HTTPS, сертификат автоматически обновляется.

Проверьте смешанный контент: скрипт, изображение или API по http:// может быть заблокирован или перехвачен.

Cookie с сессией должен иметь подходящие атрибуты Secure, HttpOnly и SameSite в соответствии с архитектурой. Не храните долговечный токен в доступном любому скрипту месте без понимания риска XSS.

Настройте security headers по документации фреймворка и OWASP. Content Security Policy внедряйте сначала в режиме наблюдения, чтобы не сломать необходимые ресурсы случайным правилом.

Обновляйте зависимости

Устаревший пакет может иметь известную уязвимость. Включите уведомления репозитория и регулярно просматривайте обновления.

Не обновляйте все зависимости автоматически прямо в production. Создайте отдельную ветку, прочитайте changelog, выполните тесты и проверьте приложение.

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

Фиксируйте lock-файл. Установка должна воспроизводить проверенные версии, а не случайный набор последнего дня.

Настройте резервные копии

Копия кода в Git не является копией базы и загруженных файлов. Определите для каждого хранилища:

· частоту backup;

· срок хранения;

· шифрование;

· отдельное расположение;

· ответственного;

· допустимую потерю данных;

· время восстановления.

Автоматический статус «backup completed» ничего не говорит о восстановлении. Разверните копию в изолированной тестовой среде и проверьте записи, связи и файлы.

Хранить копию на том же сервере недостаточно: ошибка диска или учетной записи затронет обе.

Подготовьте реакцию на инцидент

Запишите простой порядок:

1. Ограничить затронутый доступ.

2. Сохранить журналы и время события.

3. Отозвать скомпрометированные ключи.

4. Восстановить известную рабочую версию.

5. Проверить целостность данных.

6. Сообщить ответственным и выполнить обязательные уведомления.

7. Добавить защиту и тест.

Не очищайте сервер и логи до сохранения фактов. Но и не оставляйте открытый ключ работать ради расследования.

Заранее храните контакты хостинга, регистратора и провайдеров отдельно от самого сайта.

Наблюдайте за сайтом

Минимальное наблюдение включает доступность, серверные ошибки, неуспешные входы, сбои форм и изменения административных ролей.

Сигнал должен вести к действию. Тысяча предупреждений, которые никто не читает, хуже нескольких понятных правил.

Не записывайте полные тела форм и авторизационные заголовки в обычный лог. Маскируйте персональные данные и секреты.

Проверяйте, что журнал доступен, когда основной сервер недоступен.

Используйте ИИ с границами

ИИ может проверить конфигурацию, предложить тесты и найти явный секрет в diff. Он не гарантирует безопасность и может предложить устаревший пакет.

Давайте узкую задачу:

Проверь текущий diff на секреты, отсутствие серверной валидации и слишком широкие права. Ничего не меняй. Для каждого замечания назови файл, строку, риск и минимальную проверку.

Затем сверяйте рекомендации с официальной документацией фреймворка и OWASP.

На курсе «Вайбкодинг на максималках» безопасность рассматривается вместе с Git, базой, API, Docker и production-деплоем.

Проведите короткую модель угроз

Не нужно начинать с большого документа. Выберите главный пользовательский путь и ответьте на четыре вопроса: что защищаем, от кого, через какую границу приходит ввод и что произойдет при успехе атаки.

Для формы заявки активами будут контакты клиента, учетная запись менеджера и доступность обработки. Возможные нарушители: бот, любопытный пользователь, бывший сотрудник или вредоносный файл. Границы: браузер, серверный endpoint, база, почтовая интеграция и административная панель.

Для каждой угрозы выберите проверку. Попробуйте отправить слишком длинное поле, повторить запрос, открыть чужую запись, загрузить файл с неверным типом и войти без второго фактора. Запишите фактический результат и владельца исправления.

Модель угроз не предсказывает все атаки. Она мешает команде защищать абстрактный «сайт» и пропустить конкретный путь к ценным данным.

Разделите production и тест

Тестовая среда не должна использовать рабочую базу и ключи только ради удобства. Иначе эксперимент coding agent может отправить настоящее письмо, изменить заказ или раскрыть реальные данные в логе.

Создайте отдельные secrets и тестовые учетные записи. Используйте обезличенные примеры. Ограничьте права тестового ключа теми операциями, которые нужны сценарию. После публикации проверьте, что preview-ссылка не индексируется и не дает административный доступ без авторизации.

При копировании production-данных в тест удалите лишние поля и проверьте резервные копии самой тестовой среды. Случайная выгрузка часто защищена хуже основной базы.

Репетиция инцидента

Один раз проиграйте простой случай: API-ключ оказался в публичном репозитории. Кто отзовет его, где создаст новый, какие сервисы перезапустит, как проверит расходы и кому сообщит?

Второй сценарий: ошибочное удаление таблицы. Найдите последнюю резервную копию и восстановите ее в отдельную среду. Замерьте время и проверьте количество записей. Фраза «у хостинга есть backup» не подтверждает, что команда умеет им воспользоваться.

После репетиции обновите инструкцию и доступы. Храните контакты и порядок действий там, где они доступны при сбое основного сайта.

Добавьте дату следующей проверки. Доступы, зависимости и люди меняются, поэтому разовый чек-лист устаревает. Раз в месяц просматривайте администраторов и обновления, раз в квартал повторяйте восстановление на отдельной среде. Период выбирайте по риску сайта, но у каждой проверки должны быть владелец и сохраненный результат.

Чек-лист первого дня

Начните с десяти действий: индивидуальные аккаунты, 2FA, ревизия ролей, secrets вне Git, серверная валидация, HTTPS, обновления, backup базы и файлов, тест восстановления и наблюдение за формой.

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