Безопасность сайта: OWASP, HTTPS, обновления и пароли

Зачем:Сайты взламывают не по личной неприязни, а автоматически и пачками, цепляясь за устаревшие плагины, слабые пароли и забытые ключи. После урока вы знаете десять самых частых классов проблем из списка OWASP Top 10 простыми словами, настраиваете HTTPS и заголовки безопасности, заводите двухфакторный вход и составляете для своего проекта короткий план защиты.

30 минут

Озвучено синтезом речи (Qwen3-TTS), голос не принадлежит человеку.

OWASP Top 10 — список самых распространённых классов уязвимостей веб-приложений. От массовых атак защищают HTTPS, обновления, пароли и второй фактор.

Кого взламывают

Первая мысль: «кому нужен мой маленький сайт?» Ответ: боту. Взломы сегодня почти всегда автоматические. Программы круглосуточно обходят адреса в интернете, стучатся в /wp-login.php, ищут файл .env, пробуют известную дыру известного плагина, и если находят, то берут то, что есть: размещают скрытую рекламу и ссылки на свои сайты, рассылают спам с вашего адреса, воруют заявки и пароли. Им всё равно, что за сайт; важно, что он открыт.

Отсюда практичный вывод. Вам не нужна оборона от спецслужб. Нужно закрыть то, что закрывается дёшево: обновления, пароли с вторым фактором, шифрование, ввод, ключи. Это скучно и работает. Остальное уже вопрос размеров проекта.

Этот урок про сайт целиком, а следующий про форму отдельно.

OWASP и его список из десяти

OWASP (Open Worldwide Application Security Project, раньше Open Web Application Security Project) это открытое некоммерческое сообщество, которое выпускает свободные материалы о безопасности приложений. Самое известное это OWASP Top 10: список десяти самых распространённых классов проблем, который обновляют раз в несколько лет. Последняя редакция вышла в 2025 году. Это не контрольный перечень, а ориентир: «вот где на практике чаще всего ломают».

Прочитаем все десять простыми словами, с тем, что делает автор небольшого сайта.

  1. A01 Нарушение контроля доступа (Broken Access Control). Человек получает то, что ему не положено: поменял номер в адресе /request/105 на 106 и увидел чужую заявку; открыл /admin, не войдя. Лечение: сервер проверяет права на каждый запрос, а не верит тому, что пришло.
  2. A02 Ошибки настройки (Security Misconfiguration). Пароль по умолчанию, открытая панель управления, включённая отладка, нет заголовков безопасности, список файлов виден всем. Лечение: настроить и проверить, отключить лишнее.
  3. A03 Сбои в цепочке поставки программ (Software Supply Chain Failures). Сайт опирается на чужое: CMS, плагины, темы, библиотеки, сборочные инструменты. Если там дыра или кто-то подменил пакет, она у вас. Лечение: обновлять, не ставить лишнего, брать из надёжных источников.
  4. A04 Сбои криптографии (Cryptographic Failures). Нет HTTPS, пароли хранятся открытым текстом или слабым хешем, секреты лежат где попало. Лечение: HTTPS везде, пароли хешировать (об этом урок об аутентификации), секреты хранить отдельно.
  5. A05 Инъекция (Injection). Введённый человеком текст превращается в код или часть запроса. Если в запрос к базе вставить текст как есть, кавычка и фрагмент SQL позволят вытащить всю базу (SQL-инъекция). Если вывести чужой текст на страницу без экранирования, чужой скрипт выполнится у других посетителей (XSS, межсайтовый скриптинг). Лечение: запросы с параметрами, экранирование при выводе, проверка ввода.
  6. A06 Небезопасный замысел (Insecure Design). Ошибка не в коде, а в идее: сброс пароля по дате рождения, форма без ограничения частоты, у которой нельзя остановить спам. Лечение: думать о злоупотреблении до разработки.
  7. A07 Сбои аутентификации (Authentication Failures). Слабые пароли, нет второго фактора, нет защиты от перебора. Лечение: длинные уникальные пароли, второй фактор, ограничение попыток.
  8. A08 Сбои целостности программ и данных (Software or Data Integrity Failures). Код или данные меняются без проверки: подключили скрипт с чужого сервера без проверки подлинности, автообновление без проверки подписи. Лечение: проверять источник, закреплять версии, у подключаемых скриптов указывать контрольную сумму (Subresource Integrity).
  9. A09 Сбои журналирования и оповещений (Security Logging and Alerting Failures). Атаку не видно, потому что ошибки и странные входы никто не записывает и не читает. Лечение: журнал ошибок и входов и оповещение о необычном.
  10. A10 Неправильная обработка исключительных ситуаций (Mishandling of Exceptional Conditions). Ошибка показывает посетителю внутренности (путь к файлам, запрос к базе) или приводит к тому, что защита «отключается». Лечение: понятное сообщение человеку, подробности в журнал, а при сбое запрещать, а не разрешать.

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

Лента попыток: что остановлено, что прошло

Это обычные автоматические попытки, которые идут на любой сайт. Включайте меры и смотрите, что остановлено.

  1. Бот перебирает пароли к странице входа в админку
    Прошло. Что это по OWASP: A07 Authentication Failures.
  2. Скрипт пробует известную дыру устаревшего плагина
    Прошло. Что это по OWASP: A03 Software Supply Chain Failures.
  3. В поле «Комментарий» вставлен скрипт, чтобы выполниться у других посетителей
    Прошло. Что это по OWASP: A05 Injection (XSS).
  4. В поле формы введена кавычка и фрагмент SQL, чтобы вытащить базу
    Прошло. Что это по OWASP: A05 Injection (SQL).
  5. Чужой в открытой сети Wi-Fi читает, что отправляет форма
    Прошло. Что это по OWASP: A04 Cryptographic Failures.
  6. Ваш сайт показан невидимым слоем на чужой странице, чтобы подменить клик
    Прошло. Что это по OWASP: A02 Security Misconfiguration.
  7. Сканер ищет файл .env и ключи в публичном репозитории
    Прошло. Что это по OWASP: A02 Security Misconfiguration.
  8. В адресе /request/105 меняют номер на 106 и читают чужую заявку
    Прошло. Что это по OWASP: A01 Broken Access Control.
  9. Бот отправляет форму заявки тысячу раз с рекламой
    Прошло. Что это по OWASP: A06 Insecure Design.

Остановлено 0 из 9. Пока ничего: сайт открыт всем, кто попробует.

Текстовая альтернатива: лента из попыток (перебор пароля, дыра в плагине, скрипт и SQL в форме, перехват в Wi-Fi, встраивание сайта в чужую страницу, поиск ключей, подмена номера в адресе, спам) и список мер. Каждая попытка останавливается хотя бы одной подходящей мерой: двухфактором или ограничением частоты, обновлением, проверкой ввода, HTTPS, заголовками, хранением секретов вне кода, проверкой прав.

Проверьте себя: что такое инъекция и как её предотвращают?

Введённый человеком текст попадает в код или запрос как часть команды. Предотвращают параметрами запросов (значение передаётся отдельно от текста запроса), экранированием при выводе на страницу и проверкой ввода на сервере.

Как выглядит инъекция

SQL-инъекция проще, чем кажется. Допустим, сайт ищет заявку по телефону так:

запрос = "SELECT * FROM requests WHERE phone = '" + phone + "'"

Если человек введёт обычный номер, всё работает. Но если он введёт ' OR '1'='1, запрос станет «выбрать все заявки, где телефон равен пустоте или единица равна единице», то есть вернёт всю таблицу. Правильно передавать значение отдельно от текста запроса:

SELECT * FROM requests WHERE phone = $1      (значение передаётся отдельно)

База сама знает, что $1 это значение, а не команда, и текст ввода никогда не станет частью запроса. Вы видели такие параметры в уроках про SQL. XSS устроен так же, только жертва другая: не база, а браузер соседнего посетителя. Современные шаблонизаторы (Svelte, например) экранируют вывод автоматически, пока вы не просите их вставить «сырой» HTML.

HTTPS и заголовки безопасности

Про сертификаты вы узнали в уроке о HTTPS и TLS и в уроке о сертификатах на практике. Здесь что к ним добавить.

  • HTTPS везде. Весь сайт, все ресурсы (иначе браузер блокирует «смешанное содержимое»), и перенаправление с http:// на https://.
  • HSTS это заголовок Strict-Transport-Security: max-age=31536000. Он говорит браузеру: в течение года ходи на этот сайт только по HTTPS, не вспоминая про http. Без него человек, набравший адрес без https, на мгновение идёт по открытому соединению, и его можно перехватить. Включайте, когда уверены, что весь сайт работает по HTTPS.
  • Content-Security-Policy (CSP) это список источников, откуда странице можно брать скрипты, стили, картинки, и куда она может отправлять формы. Скрипт, который попал в страницу через XSS, но пришёл не из разрешённого источника, браузер не выполнит. Надёжный минимум: default-src 'self'; object-src 'none'; base-uri 'self'; frame-ancestors 'none'; form-action 'self'. Подключаемые сервисы (счётчик, карта) добавляются в политику явно. Слова 'unsafe-inline' и 'unsafe-eval' почти полностью лишают политику смысла: избегайте их.
  • X-Content-Type-Options: nosniff это браузер не «угадывает» тип файла и не выполняет картинку как скрипт.
  • Referrer-Policy: strict-origin-when-cross-origin это на чужие сайты уходит только имя вашего сайта, а не полный адрес страницы (в нём могут быть данные).
  • frame-ancestors (в CSP) или старый X-Frame-Options не дают встроить ваш сайт в чужую страницу. Иначе возможен «кликджекинг»: невидимый слой с вашей кнопкой под чужой картинкой.
  • Флаги cookie (вы знаете их из урока об аутентификации): Secure (только по HTTPS), HttpOnly (недоступна скриптам), SameSite=Lax (не уходит с чужих сайтов).

Где эти заголовки задают. В настройках веб-сервера (nginx, Caddy), в файле _headers на Netlify и Cloudflare Pages (строка с путём /*, под ней заголовки с отступом) или в настройках платформы. Не на всех платформах это возможно: на GitHub Pages свои заголовки задать нельзя (часть политики можно передать через meta-тег, но не всю: frame-ancestors в meta не работает). Если без этого не обойтись, перед сайтом ставят прокси или CDN, который добавляет заголовки.

Проверяют результат бесплатной проверкой MDN HTTP Observatory: она открывает ваш сайт и выставляет оценку с перечнем того, что не настроено. Запишите оценку «до» и «после» и вернитесь к ней, когда подключите новую библиотеку: легко сломать то, что настроили.

Проверьте себя: почему в CSP не оставляют 'unsafe-inline'?

Оно разрешает выполнять скрипт, вписанный прямо в страницу, а именно так действует XSS: внедрённый скрипт оказывается внутри страницы. С ‘unsafe-inline’ политика почти не защищает.

Обновления

Больше всего сайтов ломают через устаревшее: версию CMS, плагин, тему, библиотеку. Дыры в них публикуют, а автоматические сканеры проверяют, у кого ещё не закрыто. Поэтому:

  • Обновляйте регулярно, критические исправления сразу. Для WordPress и других CMS включите автоматические обновления безопасности. Для проекта на коде: отчёт npm audit, GitHub Dependabot или аналоги.
  • Не ставьте лишнего. Каждый плагин это чужой код и ваша ответственность. Выключили и не пользуетесь, значит, удалить.
  • Берите из надёжных источников, смотрите, когда плагин последний раз обновлялся и сколько людей им пользуются. Заброшенный плагин это дыра на отсрочке.
  • Закрепляйте версии и проверяйте источники, когда подключаете скрипты с чужих серверов (это тот самый A03 и A08).
  • Есть копия, и вы знаете, как её развернуть (урок про резервные копии в части про инфраструктуру): обновление иногда ломает сайт, и откат должен быть возможен.

Пароли и второй фактор

Самый частый путь внутрь: украденный или угаданный пароль. Что работает.

  • Уникальный длинный пароль для каждого сайта, который помнит менеджер паролей (Bitwarden, KeePass и другие; встроенные менеджеры браузеров и систем тоже годятся). Если один сайт потеряет базу, остальные остаются закрыты.
  • Длина важнее хитрости. Современные рекомендации (NIST SP 800-63B) советуют длинные пароли, разрешать вставку и менеджеры, проверять по спискам утёкших паролей и не менять пароль по расписанию без причины: частая смена рождает «Пароль1», «Пароль2».
  • Второй фактор (2FA): кроме пароля нужно что-то ещё. Приложение-аутентификатор (коды, которые меняются каждые тридцать секунд), аппаратный ключ или пасскей (из урока об аутентификации) надёжнее, чем SMS (номер можно перехватить). Но SMS лучше, чем ничего.
  • Защищайте цепочку. Первым защищайте почту владельца: через неё сбрасываются пароли остальных. Затем регистратора домена (кто владеет доменом, тот владеет сайтом), хостинг или сервис выкладки, репозиторий и админку сайта.
  • Резервные коды второго фактора сохраните в надёжное место: потерянный телефон не должен стать потерянным сайтом.
  • Пароли посетителей (если у вас есть вход) не храните сами: только хеш медленной функцией (argon2id, bcrypt), как в уроке об аутентификации. Лучше не создавать вход, если без него можно обойтись.

Проверить, не утёк ли ваш адрес почты в известных взломах, можно в сервисе Have I Been Pwned (источник справа): он показывает, в каких утечках встречался адрес.

Секреты

Ключ к платёжной системе, пароль к базе, токен приёмника: всё это секреты. Их главное правило: секрет не должен попасть в репозиторий. Для этого его кладут в переменные окружения сервера или платформы (так делают все сервисы выкладки) или в менеджер секретов, а локальный файл .env вписывают в .gitignore. Если секрет всё же попал в репозиторий, даже на минуту, считайте его скомпрометированным: отзовите и выпустите новый. Автоматические сканеры находят ключи в публичных репозиториях за секунды, и удаление файла не удаляет его из истории.

Если всё-таки взломали

Скажите себе заранее, что вы будете делать, пока не горит.

  1. Остановить ущерб: отключить сайт (страница-заглушка), закрыть вход в админку.
  2. Сменить доступы: пароли и ключи всех связанных аккаунтов, отозвать токены, закрыть чужие сессии.
  3. Восстановить из чистой копии и обновить всё, что было устаревшим. Просто «вычистить» взломанный сайт ненадёжно: вы не знаете, что осталось.
  4. Найти, как вошли, по журналам, иначе повторится.
  5. Оценить, утекли ли данные людей, и если да, то сообщить, кому положено по закону. Когда утечка касается персональных данных, у оператора есть обязанности и сроки; о них в уроке про 152-ФЗ.

Практика

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

Проверка читает текст: она убедится, что в заголовках есть HSTS, CSP с нужными правилами без 'unsafe-inline', nosniff и политика реферера, а в таблице названа защита аккаунтов. Она не может проверить, что вы и правда поставили второй фактор. Это сделаете вы: откройте настройки каждого аккаунта и включите его, а потом проверьте настоящий сайт в Observatory.

Что было не так раньше

В 2000-х «безопасность» часто значила один пароль на всё и отсутствие обновлений: сайты на самодельных скриптах не обновлялись годами. Формы собирали SQL-запрос склейкой строк, а пароли хранили открытым текстом, о чём потом узнавали из публикаций об утечках. Появились платформы и стандарты, а с ними привычки: HTTPS стал нормой (с бесплатными сертификатами), браузеры начали предупреждать о небезопасных сайтах, а списки OWASP стали общим языком. Но главный враг остался прежним: «потом обновлю» и «у меня нечего красть».

Практика

Готовлю вашу страницу…

Тест

Вопрос 1 из 6

Соедините класс проблем из OWASP Top 10 с тем, как он выглядит на сайте

Подберите пару к каждому пункту.

Карточки

Эти карточки попадут в повторение, когда вы завершите урок.

  • Что такое OWASP Top 10?

    Ответ

    Список из десяти самых распространённых классов уязвимостей веб-приложений, который составляет сообщество OWASP. Это не полный перечень проверок, а ориентир: версия 2025 года начинается с нарушения контроля доступа.

  • Что нужно для защищённого соединения?

    Ответ

    HTTPS с действующим сертификатом, перенаправление с http, HSTS (браузер ходит только по https), у cookie флаги Secure, HttpOnly и SameSite.

  • Зачем CSP и какие правила обязательны?

    Ответ

    Ограничивает источники кода и адреса отправки форм. Базовый набор: default-src 'self', object-src 'none', base-uri 'self', frame-ancestors, form-action 'self'. Без 'unsafe-inline'.

  • Какие аккаунты защищают в первую очередь?

    Ответ

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

  • Где хранить ключи и пароли?

    Ответ

    В переменных окружения и менеджере секретов, не в коде и не в репозитории (.env в .gitignore). Если секрет попал в репозиторий, его отзывают и выпускают новый.

Источники

Дальше

Теперь вы знаете: OWASP: основы безопасности сайта, гигиена сайта: HTTPS, обновления, пароли и двухфакторный вход, заголовки безопасности и HTTPS.