DNS RobotDNS Propagation Checker
ГлавнаяDNSWHOISIPSSL
DNS RobotDNS Propagation Checker

DNS-инструменты нового поколения

Политика конфиденциальностиУсловия использованияО насБлогКонтакты

DNS Инструменты

DNS ПоискТест Скорости DNSДомен в IPNS ПоискMX ПоискПоказать все

Инструменты Email

Проверка SPF записиПроверка DMARCПроверка DKIMТест SMTPАнализ заголовков EmailПоказать все

Инструменты для сайтов

WHOIS ПоискПроверка хостингаДоступность доменаПоиск поддоменовОпределение CMSПоказать все

Сетевые инструменты

Ping инструментТрассировкаПроверка портовПроверка HTTP заголовковПроверка SSL сертификатаПоказать все

IP Инструменты

IP ПоискМой IP адресПроверка IP в чёрных спискахIP в имя хостаASN ПоискПоказать все

Утилиты

Сканер QR кодаГенератор QR кодаUPI QR Code GeneratorWiFi QR Code GeneratorПереводчик азбуки МорзеПоказать все
© 2026 DNS Robot. Разработано: ❤ Shaik Brothers
Все системы работают
Made with
Главная/Блог/Безопасность сайта: как защитить сайт на каждом уровне (2026)

Безопасность сайта: как защитить сайт на каждом уровне (2026)

Shaik Vahid29 сент. 2026 г.30 мин чтения
Безопасность сайта: шесть уровней защиты — домен и DNS, TLS, HTTP-заголовки, приложение, зависимости и сервер
Безопасность сайта: шесть уровней защиты — домен и DNS, TLS, HTTP-заголовки, приложение, зависимости и сервер

Ключевой вывод

Безопасность сайта строится уровнями: закрепите за собой домен и DNS (registrar lock, DNSSEC, CAA), включите современный TLS с HSTS, отправляйте строгий набор HTTP-заголовков безопасности, хешируйте пароли с Argon2id и прикройте вход MFA и rate limiting, проверяйте входные данные и права доступа на сервере, фиксируйте версии зависимостей и проводите их аудит, закройте все порты, которые вы не обслуживаете, и ведите журналы, по которым можно заметить взлом. Для каждой практики ниже приведены точная конфигурация и бесплатный способ убедиться, что она действительно работает: меры защиты, которую вы не проверили, у вас фактически нет.

Advertisement

Что на самом деле означает безопасность сайта

Безопасность сайта — это набор мер защиты, которые не дают взломать сайт или веб-приложение, подменить его содержимое, использовать его для атак на собственных посетителей или незаметно выкачать из него данные. Это не один продукт и не одна настройка. Это цепочка решений, которая начинается у регистратора домена и проходит через DNS, TLS, HTTP-заголовки, которые отправляет ваш сервер, код, обрабатывающий вход в систему и пользовательский ввод, сторонние пакеты, на которых построено приложение, сам сервер и, наконец, журналы, из которых вы узнаёте, что что-то пошло не так.

Думать уровнями стоит потому, что так думают атакующие. Согласно отчёту Verizon 2026 Data Breach Investigations Report, 31 % утечек теперь начинается с эксплуатации уязвимости в ПО — впервые этот путь обогнал украденные учётные данные как самый распространённый способ проникновения, а 48 % всех утечек связаны с программами-вымогателями. Достаточно одного пропущенного патча, утёкшего API-ключа или админки без ограничения частоты запросов. Ни одна из мер в этом руководстве не экзотична: взламывают обычно те сайты, которые пропустили базовые вещи на одном уровне, пока доводили до блеска другой.

Руководство построено снаружи внутрь. Для каждой практики объясняется, почему она важна, что именно настроить и как это проверить — командой или бесплатным инструментом, потому что самая частая проблема, которую мы видим при проверке HTTP-заголовков и проверке SSL-сертификата, — это не неверное решение, а настройка, которую кто-то считал включённой, но так и не проверил.

Заметка

Если у вас есть всего час: включите registrar lock и MFA у регистратора, принудительно переведите сайт на HTTPS с HSTS, добавьте заголовки безопасности из таблицы в разделе «Уровень 3», хешируйте пароли с Argon2id, обновите все зависимости с известными CVE и закройте все порты, кроме 80 и 443. Это перекрывает точки входа, через которые происходит подавляющее большинство реальных взломов сайтов.

Стек веб-безопасности: шесть уровней защиты

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

УровеньЧто делают атакующиеОсновные практикиКак проверить
1. Домен и DNSУгоняют домен, меняют NS-серверы, захватывают «висячие» поддомены, получают поддельные сертификатыRegistrar lock, MFA, DNSSEC, CAA, аудит устаревших записейWHOIS-поиск, DNS-поиск, Поиск поддоменов
2. Транспорт (TLS)Понижают соединение до HTTP, снимают шифрование, эксплуатируют устаревшие шифры и просроченные сертификатыTLS 1.2+, HSTS с preload, автоматическое продлениеПроверка SSL-сертификата
3. HTTP-заголовкиВнедряют скрипты (XSS), встраивают сайт во фрейм для кликджекинга, пользуются угадыванием типа содержимого, перехватывают утечки через RefererCSP, frame-ancestors, nosniff, Referrer-Policy, Permissions-PolicyПроверка HTTP-заголовков
4. ПриложениеCredential stuffing, инъекции, нарушение контроля доступа, CSRF, небезопасная загрузка файловArgon2id + MFA + rate limiting, параметризованные запросы, авторизация на сервере, cookie с SameSiteКод-ревью, OWASP ZAP, Тест надёжности пароля
5. ЗависимостиОтравленные пакеты, известные CVE в библиотеках, скомпрометированные CI-пайплайныLockfile, аудит, фиксированные версии, SBOM, токены с минимальными правамиnpm audit, Dependabot, Trivy
6. Сервер и эксплуатацияОткрытые порты, учётные данные по умолчанию, отсутствующие патчи, нет резервных копий, нет журналовФайрвол, SSH только по ключам, патчи, резервное копирование 3-2-1, централизованное логированиеПроверка портов, Проверка IP в чёрных списках, Проверка здоровья домена

Совет

Двигайтесь сверху вниз. Уровни 1–3 — это конфигурация, которую можно закончить за полдня, и она защищает сразу все страницы. Уровни 4–6 — постоянные привычки, которые должны стать частью код-ревью и процесса деплоя.

Advertisement

Уровень 1: защитите домен и DNS

Всё остальное в этом руководстве предполагает, что домен по-прежнему под вашим контролем. Если атакующий может войти в ваш аккаунт у регистратора или сменить NS-серверы, он направит ваш трафик куда угодно, получит действительный сертификат на ваше имя и будет читать всю адресованную вам почту — а ни одна строка кода вашего приложения даже не выполнится. Поэтому защита домена и DNS — первая из лучших практик веб-безопасности, и почти целиком это вопрос конфигурации.

Начните с WHOIS-поиска по собственному домену и убедитесь в трёх вещах: среди статусов есть clientTransferProhibited, до окончания регистрации больше года, а регистратор — тот, у которого у вас действительно есть аккаунт. Удивительно часто домен компании числится в аккаунте бывшего подрядчика. В нашем руководстве по WHOIS-поиску разобраны все коды статусов, которые вы увидите.

Registrar lock, MFA и напоминания об окончании срока

Включите registrar lock (его также называют блокировкой трансфера), чтобы домен нельзя было перенести к другому регистратору, пока вы явно не снимете блокировку, и включите многофакторную аутентификацию в самом аккаунте регистратора. Аккаунты у регистраторов — излюбленная цель фишинга именно потому, что один вход открывает доступ ко всему, что от него зависит. Если регистратор позволяет, используйте аппаратный ключ или приложение-аутентификатор, а не SMS.

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

  • Registry lock (ручная блокировка на уровне реестра, снимаемая только через отдельный канал) стоит дополнительных денег для домена, от которого зависит бизнес: он не даёт сменить NS-серверы даже при взломанном аккаунте у регистратора.

  • Разделите роли. Кто платит за домен, какой аккаунт им владеет и кто предоставляет DNS — всё это должно быть задокументировано и не привязано к почтовому ящику одного сотрудника.

  • Включите защиту данных в WHOIS, чтобы ваши контакты не стали картой для фишинга, и укажите в аккаунте ролевой адрес, который кто-то регулярно читает, например domains@.

Подпишите зону с помощью DNSSEC

DNSSEC подписывает вашу DNS-зону, чтобы резолвер мог распознать поддельные ответы. Без него атакующий, способный отравить кеш резолвера, отправит ваших посетителей на поддельный сервер, а браузер при этом будет показывать ваше доменное имя. Большинство управляемых DNS-провайдеров (Cloudflare, Route 53, Google Cloud DNS и многие регистраторы) включают его одним переключателем; единственный ручной шаг — опубликовать DS-запись у регистратора. Проверьте результат командой dig или проверкой DNSSEC в инструменте Проверка здоровья домена:

bash
dig +dnssec +short yourdomain.com A
# A signed zone returns the record AND an RRSIG line:
# 203.0.113.10
# A 13 2 3600 20261015000000 20260924000000 34505 yourdomain.com. Kx3f...==

dig +short yourdomain.com DS
# A DS record at the parent zone proves the chain of trust is complete
# 34505 13 2 6A1B...C9

Ограничьте выпуск сертификатов записью CAA

Запись CAA (RFC 8659) сообщает центрам сертификации, кому из них разрешено выпускать сертификаты для вашего домена. Каждый публичный центр сертификации обязан проверять её перед выпуском, поэтому запись CAA закрывает дверь атакующему, который сумел обмануть проверку домена в каком-то другом центре. Три записи покрывают типичные случаи: кто может выпускать сертификаты, кто может выпускать wildcard-сертификаты и куда сообщать об отклонённом запросе:

dns
yourdomain.com.  CAA 0 issue "letsencrypt.org"
yourdomain.com.  CAA 0 issuewild ";"
yourdomain.com.  CAA 0 iodef "mailto:security@yourdomain.com"

Внимание

Прежде чем добавлять CAA, составьте список всех центров сертификации, которые сейчас выпускают для вас сертификаты, включая тот, что стоит за вашим CDN или панелью хостинга (Cloudflare чередует несколько центров; многие хостинги используют Sectigo или Let's Encrypt). Запись CAA, в которой нет вашего реального центра сертификации, молча сломает следующее продление. Сначала узнайте текущего издателя с помощью проверки SSL-сертификата.

Аудит устаревших записей: subdomain takeover

Subdomain takeover (захват поддомена) происходит, когда DNS-запись всё ещё указывает на сервис, которым вы больше не пользуетесь: CNAME на удалённый сайт GitHub Pages, приложение Azure, бакет S3 или имя хоста SaaS-провайдера. Кто угодно может зарегистрировать брошенную цель и раздавать контент на old-app.yourdomain.com от вашего имени — вместе с действительным сертификатом. Это одна из самых частых находок в программах bug bounty, потому что о существовании такой записи никто не помнит.

Проверьте домен через Поиск поддоменов: он читает журналы Certificate Transparency, поэтому вы увидите все имена хостов, на которые когда-либо выпускался сертификат. Затем разрешите каждое из них через DNS-поиск и удалите все записи, цель которых возвращает NXDOMAIN или страницу провайдера «no such app». Повторяйте раз в квартал и сделайте удаление DNS-записи обязательной частью вывода любого сервиса из эксплуатации.

Совет

Certificate Transparency — это ещё и система раннего предупреждения: Cert Spotter и CT-мониторинг Cloudflare могут присылать письмо каждый раз, когда любой центр сертификации выпускает сертификат для вашего домена. Неожиданный сертификат часто становится первым видимым признаком компрометации DNS или аккаунта у регистратора.

Уровень 2: HTTPS и TLS как положено

HTTPS — уже не лучшая практика, а базовый минимум: браузеры помечают страницы на обычном HTTP как «Не защищено». По-настоящему защищённый сайт от просто зашифрованного сегодня отличают принимаемые версии TLS, то, можно ли вообще обратиться к нему по HTTP, и то, насколько хорошо автоматизировано продление, чтобы пережить сокращение срока действия сертификатов, начавшееся в марте 2026 года.

Advertisement

Минимум TLS 1.2, предпочтительно TLS 1.3

TLS 1.0 и 1.1 официально признаны устаревшими в RFC 8996 в 2021 году, и ни один современный браузер их не согласует. Отключите их на сервере, отдавайте предпочтение TLS 1.3 (в нём нет ни одного известного слабого шифра, а рукопожатие занимает один круговой обмен) и оставляйте TLS 1.2 только с AEAD-наборами шифров, например ECDHE-ECDSA-AES128-GCM-SHA256 или ECDHE-RSA-CHACHA20-POLY1305.

При проверке снаружи важны две строки: согласованный протокол и Verify return code: 0 — она означает, что вся цепочка сертификатов прошла проверку. Отсутствующий промежуточный сертификат — самая частая причина жалоб вида «в Chrome работает, а в curl и на Android — нет»; в нашем руководстве по цепочке SSL-сертификатов показано, как это исправить, а проверка SSL-сертификата сразу указывает на неполную цепочку. Вот такая проверка для dnsrobot.net:

bash
echo | openssl s_client -connect dnsrobot.net:443 -servername dnsrobot.net 2>/dev/null \
  | grep -E 'Protocol|Cipher|Verify return'

# Protocol  : TLSv1.3
# Cipher    : TLS_AES_256_GCM_SHA384
# Verify return code: 0 (ok)

# Confirm the old versions are refused:
openssl s_client -connect dnsrobot.net:443 -tls1_1 2>&1 | grep -iE 'alert|no protocols'

Заметка

Списки шифров — то место, где скопированные конфиги устаревают. Вместо того чтобы писать их вручную, сгенерируйте актуальный рекомендуемый блок конфигурации для nginx, Apache, Caddy или HAProxy в Mozilla SSL Configuration Generator и выберите профиль «Intermediate», если вам не нужно поддерживать совсем старых клиентов.

HSTS: запретите браузеру возвращаться к HTTP

Одного редиректа с HTTP на HTTPS недостаточно. Самый первый запрос посетителя к http://yourdomain.com всё равно уходит открытым текстом, и атакующий в той же сети может ответить на него раньше, чем сработает ваш редирект. HTTP Strict Transport Security (RFC 6797) решает эту проблему: увидев заголовок один раз, браузер переписывает каждый последующий URL http:// для вашего домена на https:// ещё до отправки запроса.

Задайте max-age не меньше одного года (31536000 секунд), добавьте includeSubDomains, когда все поддомены будут работать по HTTPS, а затем отправьте домен на hstspreload.org, чтобы он был жёстко прописан в Chrome, Firefox, Safari и Edge. Preload полностью закрывает брешь первого визита. Проверьте заголовок с помощью проверки HTTP-заголовков: она учитывает HSTS в итоговой оценке безопасности от A до F.

http
Strict-Transport-Security: max-age=31536000; includeSubDomains; preload

Внимание

HSTS — дверь, которая открывается только в одну сторону. Когда includeSubDomains попадает в preload-список, любой поддомен, который не может отдавать действительный HTTPS, включая внутренние инструменты и забытый хост dev., становится недоступен в браузерах. Внедряйте поэтапно: max-age=300 на неделю, затем на месяц, затем на год — и только после этого добавляйте preload.

Сертификаты на 47 дней: автоматизируйте продление уже сейчас

Голосование CA/Browser Forum SC-081 поэтапно сокращает максимальный срок действия всех публичных TLS-сертификатов. Первое сокращение вступило в силу 15 марта 2026 года, так что любой сертификат, который вы покупаете или продлеваете сегодня, уже ограничен 200 днями, а к 2029 году сертификат придётся менять примерно каждые шесть недель:

Дата вступления в силуМаксимальный срок действия сертификатаПовторное использование проверки домена
До 15 марта 2026 года398 дней398 дней
15 марта 2026 года200 дней200 дней
15 марта 2027 года100 дней100 дней
15 марта 2029 года47 дней10 дней

Ручное продление такой график не переживёт. Лучшая практика — полностью автоматический выпуск через ACME: Let's Encrypt или Google Trust Services через certbot, acme.sh, Caddy или встроенные автоматические сертификаты Cloudflare, Vercel, Netlify и большинства панелей хостинга. Проверьте продление заранее, до того как оно понадобится (certbot renew --dry-run для certbot); ищите прежде всего запись CAA или правило файрвола, добавленные после прошлого продления и теперь блокирующие проверку домена. Что бы вы ни использовали, следите за сроком действия и снаружи: проверка SSL-сертификата показывает, сколько дней осталось, а просроченный сертификат превращает каждый визит в полноэкранное предупреждение браузера.

Уровень 3: HTTP-заголовки безопасности

Заголовки безопасности — это инструкции, которые сервер даёт браузеру о том, что можно и чего нельзя делать с вашими страницами: какие скрипты могут выполняться, можно ли встраивать страницу во фрейм, может ли браузер угадывать тип содержимого и что сообщать другим сайтам о том, откуда пришёл посетитель. Они ничего не стоят, применяются сразу ко всем страницам и блокируют целые классы атак. Кроме того, именно на этом уровне большинство сайтов хотя бы частично ошибается — поэтому проверка HTTP-заголовков и выставляет им оценку. Вот что отправляет dnsrobot.net (оставлены только заголовки безопасности):

bash
curl -sI https://dnsrobot.net/ | grep -iE 'strict-transport|content-security|x-frame|x-content-type|referrer-policy|permissions-policy'

strict-transport-security: max-age=31536000; includeSubDomains; preload
content-security-policy: default-src 'self'; script-src 'self' ... https://*.googletagmanager.com; frame-ancestors 'none'; base-uri 'self'; form-action 'self'
x-frame-options: DENY
x-content-type-options: nosniff
referrer-policy: strict-origin-when-cross-origin
permissions-policy: camera=(self), microphone=(), geolocation=(), payment=(), usb=()

Семь заголовков, которые должен отправлять каждый сайт

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

ЗаголовокРекомендуемое значениеОт чего защищает
Strict-Transport-Securitymax-age=31536000; includeSubDomains; preloadПонижение протокола, кража cookie по HTTP
Content-Security-Policyscript-src на основе nonce с 'strict-dynamic'; object-src 'none'; base-uri 'none'; frame-ancestors 'none'Межсайтовый скриптинг (XSS), внедрение данных, кликджекинг
X-Content-Type-OptionsnosniffMIME-сниффинг, превращающий загруженный файл в исполняемый скрипт
Referrer-Policystrict-origin-when-cross-originУтечка полных URL (токенов, поисковых запросов) третьим сторонам
Permissions-Policycamera=(), microphone=(), geolocation=(), payment=()Скрытое использование мощных API браузера сторонними скриптами
X-Frame-OptionsDENY (устаревший запасной вариант для frame-ancestors)Кликджекинг в браузерах без поддержки CSP Level 2
Cross-Origin-Opener-Policysame-originМежоконные атаки через window.opener

Content Security Policy, которая не ломает сайт

Content Security Policy — самая эффективная защита от XSS: она не даёт внедрённым скриптам выполниться, даже если уязвимость для инъекции существует. Подвох в том, что строгая политика ломает любой встроенный скрипт или сторонний тег, о котором вы забыли. Современный подход, который рекомендует Google и который описан на MDN, — политика на основе nonce: сервер генерирует случайный nonce для каждого ответа, добавляет его в каждый тег script, который выводит намеренно, а всё остальное браузер выполнять отказывается.

'strict-dynamic' делает такую политику практичной: скрипт с nonce может подгружать другие скрипты (аналитику, менеджеры тегов, виджеты), и не нужно вносить каждый из них в белый список, а токены https: и 'unsafe-inline' современные браузеры игнорируют — они служат лишь запасным вариантом для старых. Начните с Content-Security-Policy-Report-Only, неделю понаблюдайте за отчётами о нарушениях, затем переключитесь в режим блокировки. У Next.js, Rails и Django есть встроенная поддержка nonce; статические сайты могут вместо этого использовать script-src на основе хешей.

http
Content-Security-Policy:
  script-src 'nonce-r4nd0m1z3dV4lu3' 'strict-dynamic' https: 'unsafe-inline';
  object-src 'none';
  base-uri 'none';
  frame-ancestors 'none';
  form-action 'self';
  report-to csp-endpoint

<!-- Only scripts carrying the nonce run; strict-dynamic lets them load their own dependencies -->
<script nonce="r4nd0m1z3dV4lu3" src="/app.js"></script>

Заметка

Политика на основе белого списка, например script-src 'self' https://cdn.example.com, лучше, чем ничего, но любой JSONP-эндпоинт или старая библиотека на разрешённом хосте позволит её обойти. Если вы пока не можете использовать nonce, задайте хотя бы object-src 'none' и base-uri 'none' — это сразу закрывает два распространённых способа обхода.

Кликджекинг: frame-ancestors и X-Frame-Options

При кликджекинге ваш сайт невидимо загружается внутри страницы атакующего, и посетителя вынуждают нажать кнопку, которую он не видит. frame-ancestors 'none' в CSP (или 'self', если вы встраиваете собственные страницы) предотвращает это во всех современных браузерах, а X-Frame-Options: DENY защищает старые. Если вы сознательно предлагаете встраиваемый виджет, сделайте исключение только для этого пути и только для тех источников, которым оно нужно; в нашем руководстве по X-Frame-Options разобраны точные серверные правила и ошибки «refused to connect», с которыми вы столкнётесь при тестировании.

nosniff, Referrer-Policy, Permissions-Policy и COOP

X-Content-Type-Options: nosniff не даёт браузеру переопределять Content-Type на свой лад — а именно так загруженное пользователем «изображение» с HTML внутри превращается в исполняемую страницу. Referrer-Policy: strict-origin-when-cross-origin (значение по умолчанию в современных браузерах, но задайте его явно) передаёт другим сайтам только ваш источник (origin), поэтому токены сброса пароля и поисковые запросы в URL остаются приватными. Permissions-Policy отключает функции браузера, которые вы не используете, чтобы скомпрометированный сторонний скрипт не мог включить камеру или прочитать геолокацию. Cross-Origin-Opener-Policy: same-origin разрывает связь window.opener со страницами, которые вы открываете, и блокирует целый класс межоконных атак.

Важны и заголовки, которые нужно удалить: Server и X-Powered-By сообщают сканерам уязвимостей точные версии ПО, а X-XSS-Protection устарел и в старых браузерах может приводить к ошибкам, поэтому задайте ему значение 0 или уберите его. Определение CMS показывает, что сканер узнаёт о вашем стеке по одним только заголовкам.

Совет

Задавайте заголовки один раз на периметре (CDN, обратный прокси или middleware фреймворка), а не для каждой страницы отдельно. В Next.js это файл proxy или middleware; в nginx — блок add_header в контексте server; в Apache — Header always set. Затем после каждого деплоя заново запускайте проверку HTTP-заголовков: новая версия фреймворка или настройка CDN может незаметно убрать один из них.

Уровень 4: аутентификация, устойчивая к credential stuffing

Атакующие редко подбирают пароли по одному. Они прогоняют миллиарды пар «email — пароль», утёкших с других сайтов (credential stuffing), а остальное добывают фишингом. Поэтому лучшая практика аутентификации состоит из трёх частей: хранить пароли так, чтобы утечка базы данных не стала утечкой паролей, сделать украденный пароль бесполезным самим по себе и сделать перебор слишком медленным, чтобы он имел смысл. В OWASP Top 10:2025 категория Authentication Failures (ошибки аутентификации) занимает позицию A07.

Advertisement

Хешируйте пароли с Argon2id или bcrypt

Никогда не храните пароли в открытом виде и никогда не храните их быстрые хеши. MD5, SHA-1 и даже SHA-256 спроектированы быстрыми, поэтому утёкшую таблицу таких хешей можно перебирать со скоростью миллиардов попыток в секунду на одной видеокарте. Используйте медленную функцию хеширования паролей с высокими требованиями к памяти и уникальную соль для каждого пароля. OWASP Password Storage Cheat Sheet рекомендует в таком порядке:

  • Argon2id минимум с 19 МиБ памяти, 2 итерациями и степенью параллелизма 1 (или 46 МиБ с 1 итерацией).

  • scrypt с N = 2^17, r = 8, p = 1, если Argon2 недоступен.

  • bcrypt с коэффициентом сложности (work factor) 10 или выше (учитывайте ограничение на входные данные в 72 байта: предварительное хеширование более длинных паролей требует аккуратности).

  • PBKDF2-HMAC-SHA256 с 600 000 итераций — только если этого требует соответствие FIPS.

javascript
// Node.js with the argon2 package
import argon2 from "argon2";

const hash = await argon2.hash(password, {
  type: argon2.argon2id,
  memoryCost: 19456, // KiB = 19 MiB
  timeCost: 2,
  parallelism: 1,
});

// Later, on login:
const ok = await argon2.verify(hash, submittedPassword);

Заметка

Подберите параметры так, чтобы вычисление одного хеша занимало примерно 100–250 мс на сервере входа. Для реального пользователя это незаметно, а атакующего ограничивает несколькими тысячами попыток в секунду на ядро вместо миллиардов. При повышении параметров перехешируйте пароль при успешном входе — тогда старые хеши обновятся сами.

Правила для паролей, которые действительно помогают (NIST SP 800-63B)

Правила состава, которые большинство сайтов всё ещё навязывает (одна заглавная буква, один спецсимвол, смена каждые 90 дней), порождают предсказуемые пароли вроде Summer2026! и подталкивают людей использовать их повторно. Актуальные рекомендации NIST SP 800-63B заменяют их правилами, которые измеряют то, что действительно важно:

  • Минимум 8 символов, если также требуется MFA, и не менее 15 символов для пароля, который используется без второго фактора; разрешайте длину не меньше 64 символов.

  • Никаких правил состава и никакой принудительной периодической смены; требуйте смену пароля только при признаках компрометации.

  • Проверяйте каждый новый пароль по базе утечек (range API сервиса Have I Been Pwned позволяет делать это, не передавая сам пароль) и отклоняйте пароли, которые уже утекли.

  • Разрешайте вставку из буфера обмена и менеджеры паролей, принимайте пробелы и Unicode и показывайте индикатор надёжности, основанный на энтропии, а не на правилах.

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

MFA и passkeys

Многофакторная аутентификация превращает украденный пароль в тупик. Предлагайте её всем и делайте обязательной для администраторов, финансовых сотрудников и службы поддержки. Ранжируйте варианты по устойчивости к фишингу: passkeys и ключи безопасности FIDO2 невозможно выманить фишингом, потому что учётные данные привязаны к вашему настоящему источнику (origin); приложения-аутентификаторы (TOTP) — хороший вариант; SMS-коды лучше, чем ничего, но их можно перехватить через подмену SIM-карты (SIM swapping). Passkeys поддерживаются во всех современных браузерах и операционных системах и полностью избавляют от пароля, а значит, и от credential stuffing как класса атак.

Защищайте путь восстановления так же тщательно, как вход: храните коды восстановления в виде хешей, для сброса по email используйте одноразовые токены, которые истекают в течение 15 минут, и откажитесь от контрольных вопросов.

Rate limiting, блокировка и защита от ботов

Ограничивайте частоту запросов к эндпоинтам входа, регистрации, сброса пароля и MFA по IP-адресу и по учётной записи, а после достижения лимита возвращайте 429 Too Many Requests с заголовком Retry-After (в нашем руководстве по ошибке HTTP 429 описано, как должны реагировать клиенты). Дополните это нарастающей задержкой или временной блокировкой после повторных неудачных попыток входа в одну учётную запись, а для эндпоинтов, на которые идут распределённые атаки, — CAPTCHA или проверкой proof-of-work. Записывайте в журнал каждую неудачную попытку входа с IP-адресом источника, чтобы картина атаки credential stuffing была видна через минуты, а не через месяцы.

nginx
# nginx: 5 login attempts per minute per client IP
limit_req_zone $binary_remote_addr zone=login:10m rate=5r/m;

location = /api/login {
    limit_req zone=login burst=4 nodelay;
    limit_req_status 429;
    proxy_pass http://app;
}

Внимание

Показывайте одинаковое сообщение об ошибке для «неизвестного пользователя» и «неверного пароля» и добейтесь одинакового времени ответа в обоих случаях (хешируйте фиктивный пароль, если пользователя не существует). Иначе форма входа превращается в API для перебора пользователей.

Сессии, cookie и CSRF

После входа сессионная cookie и есть пользователь, поэтому она заслуживает такой же защиты, как пароль. Основную работу выполняют три атрибута cookie и один префикс в имени:

  • Secure означает, что cookie никогда не передаётся по обычному HTTP, поэтому её нельзя перехватить в публичной сети Wi-Fi.

  • HttpOnly делает её невидимой для JavaScript, поэтому XSS-уязвимость не сможет её прочитать.

  • SameSite=Lax (или Strict для админ-панелей) не даёт отправлять её в межсайтовых POST-запросах, что нейтрализует большинство CSRF-атак.

  • Префикс __Host- заставляет браузер отклонять cookie, если у неё нет флага Secure, пути Path=/ или если задан атрибут Domain, поэтому поддомен не сможет её перезаписать.

http
Set-Cookie: __Host-session=9f1c7e2a...; Path=/; Secure; HttpOnly; SameSite=Lax; Max-Age=28800

Совет

Действия, изменяющие состояние, никогда не должны быть доступны через GET. Ссылку вроде /account/delete?id=42 может вызвать тег <img> на любой странице, которую посещает пользователь, какими бы хорошими ни были флаги ваших cookie.

CSRF: вторая линия защиты за SameSite

Межсайтовая подделка запроса (CSRF) заставляет браузер, в котором пользователь уже вошёл в систему, отправить на ваш сайт запрос, изменяющий состояние, с другой страницы. Cookie с SameSite останавливают типичный случай, но для каждого запроса, отличного от GET, сохраняйте вторую защиту: anti-CSRF-токен для сессии в скрытом поле или собственном заголовке либо проверку того, что заголовок Origin (или Sec-Fetch-Site) совпадает с вашим собственным источником. Большинство фреймворков (Django, Rails, Laravel, server actions в Next.js) делают это по умолчанию; ошибка — отключить защиту для API-эндпоинта, а затем вызывать этот эндпоинт из браузера.

Идентификаторы сессий, ротация и JWT

Генерируйте идентификаторы сессий минимум со 128 битами случайности, меняйте идентификатор при входе и при любом изменении привилегий, чтобы защититься от фиксации сессии, завершайте сессии после периода бездействия и дайте пользователям кнопку «выйти на всех устройствах», которая аннулирует сессии на сервере. JWT делайте короткоживущими (минуты, плюс refresh-токен, который можно отозвать), никогда не храните их в localStorage, где их может прочитать любой скрипт, и считайте утечку ключа подписи полноценным взломом, потому что теперь можно подделать любой токен, который им когда-либо был подписан.

Инъекции и XSS: проверяйте ввод, кодируйте вывод

Инъекции (A05:2025) и межсайтовый скриптинг — одна и та же ошибка в разных местах: данные от пользователя передаются интерпретатору (SQL, командной оболочке, LDAP-запросу, HTML-странице) так, будто это код. И исправление везде одинаковое: разделяйте данные и код и никогда не собирайте команду конкатенацией строк.

Advertisement

Параметризованные запросы вместо склейки строк

Для SQL используйте подготовленные выражения (prepared statements) или ORM, который их генерирует: тогда база данных воспринимает ввод как значение, которое никогда не может изменить структуру запроса. То же правило действует для команд оболочки (передавайте массив аргументов, а не строку), для фильтров NoSQL (отклоняйте объекты-операторы вроде {"$gt": ""} в пользовательском вводе) и для путей к файлам (нормализуйте путь и убедитесь, что он остаётся внутри нужного каталога).

javascript
// Vulnerable: the input becomes part of the query text
const rows = await db.query(`SELECT * FROM users WHERE email = '${email}'`);

// Safe: the driver sends the value separately from the query
const rows = await db.query("SELECT * FROM users WHERE email = $1", [email]);

// Python / psycopg: same idea
cur.execute("SELECT * FROM users WHERE email = %s", (email,))

Кодирование вывода останавливает XSS

Межсайтовый скриптинг возникает, когда текст, контролируемый пользователем, записывается в страницу без кодирования под тот контекст, в который он попадает. Современные шаблонизаторы (React и JSX, Vue, Jinja2, Blade, ERB) кодируют по умолчанию; сегодня XSS обычно появляется через обходные механизмы: dangerouslySetInnerHTML, v-html, |safe, innerHTML, а также при сборке URL или встроенных обработчиков событий из пользовательских данных. Кодируйте под конкретный контекст, а форматированный HTML санитизируйте специализированной библиотекой, например DOMPurify, а не регулярным выражением.

Куда попадают данныеКак кодироватьПример
Тело HTMLHTML-сущности< превращается в &lt;, " — в &quot;
Атрибут HTMLСущности для атрибутов в кавычкахВсегда заключайте значение атрибута в кавычки; кодируйте " и '
JavaScriptНе вставляйте данные в текст скрипта; передавайте их через атрибуты data- или JSON-блок <script type="application/json"></script> внутри строки превращается в \u003c/script\u003e
Параметр URLПроцентное кодированиеencodeURIComponent(value)
Значение CSSПолностью избегайте; выбирайте имена классов из белого спискаНикогда не подставляйте пользовательский ввод в style

SSRF, загрузка файлов и десериализация

Подделка запросов на стороне сервера (SSRF): если ваш сервер загружает URL, указанный пользователем (вебхуки, прокси для изображений, превью ссылок), атакующий может направить его на внутренние сервисы или на эндпоинт метаданных облака 169.254.169.254 и прочитать учётные данные. Сначала разрешайте имя хоста, отклоняйте частные и link-local диапазоны, отключайте редиректы и размещайте такие загрузчики в сегменте сети, из которого недоступно ничего внутреннего.

Загрузка файлов: проверяйте тип по содержимому, а не по расширению или Content-Type от клиента; ограничивайте размер; храните файлы вне корня веб-сервера или в объектном хранилище под случайным именем, которое генерируете вы; по возможности отдавайте их с отдельного источника с nosniff и Content-Disposition: attachment. Никогда не допускайте, чтобы загруженный файл оказался там, где веб-сервер будет его выполнять.

Десериализация и mass assignment: никогда не десериализуйте недоверенные данные в формате, который может создавать экземпляры произвольных классов (нативная сериализация Java, pickle в Python, unserialize в PHP, YAML с пользовательскими тегами); используйте JSON со схемой. Привязывайте тело запроса к явному белому списку полей, чтобы пользователь не мог отправить POST с "role": "admin" в модель, у которой случайно есть такой столбец.

Внимание

Валидация нужна для проверки формы данных (это email, положительное целое число, одно из пяти допустимых значений?), а не для безопасности. Чёрные списки, вырезающие <script> или кавычки, всегда можно обойти. Принимайте только то, что ожидаете, а затем кодируйте при выводе и параметризуйте при сохранении.

Broken Access Control: риск номер один

Broken Access Control (нарушение контроля доступа) занимает первое место в OWASP Top 10 с 2021 года и сохраняет его как A01:2025. Это не одна ошибка, а привычка: при каждом запросе проверять, кто перед вами (аутентификация), и забывать проверить, к чему этому человеку можно обращаться (авторизация). Классическая форма — небезопасная прямая ссылка на объект (IDOR): GET /api/invoices/1042 работает для владельца счёта, а заодно и для любого, кто поменяет номер.

  • Запрет по умолчанию. Каждый маршрут требует явного правила, разрешающего доступ; отсутствие правила означает 403, а не 200.

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

  • Используйте неугадываемые идентификаторы там, где это помогает (UUID), но никогда не полагайтесь на них: скрытность — не авторизация.

  • Ограничьте CORS. Access-Control-Allow-Origin: * вместе с учётными данными или отражение любого Origin, который присылает запрос, отдаёт ваш API любому сайту, который посещает пользователь.

  • Отключите листинг каталогов, заблокируйте .git, .env, файлы резервных копий и конфигурации на уровне веб-сервера и не выставляйте админ-панели в публичный интернет — или закройте их MFA и белыми списками IP.

  • Ограничивайте частоту и логируйте ошибки авторизации. Всплеск ответов 403 в одной сессии — это идущая атака перебора.

javascript
// Express: ownership check on every object access
app.get("/api/invoices/:id", requireAuth, async (req, res) => {
  const invoice = await Invoice.findById(req.params.id);
  if (!invoice || invoice.ownerId !== req.user.id) {
    return res.status(404).end(); // 404, not 403: don't confirm the record exists
  }
  res.json(invoice);
});

Заметка

Тестируйте контроль доступа так, как это делает атакующий: войдите под пользователем с минимальными правами, перехватите все запросы и повторите каждый из них с идентификаторами другого пользователя и без заголовка Authorization. Автоматические сканеры находят инъекции, но почти никогда не находят ошибки авторизации — поэтому такие ошибки живут годами.

Уровень 5: зависимости и цепочка поставок ПО

В типичном веб-приложении, возможно, 5 % кода написали вы, а 95 % — скачали. Поэтому категория Software Supply Chain Failures (сбои цепочки поставок ПО) впервые появилась в OWASP Top 10 2025 года сразу на позиции A03, а эксплуатация уязвимостей обогнала украденные учётные данные в DBIR 2026. В сентябре 2025 года из-за одного мейнтейнера, попавшегося на фишинг, вредоносный код для кражи криптовалюты оказался в chalk, debug и ещё 16 npm-пакетах, которые вместе скачивают более двух миллиардов раз в неделю; каждый проект, установивший в этот промежуток незафиксированную версию, получил его автоматически.

  • Коммитьте lockfile (package-lock.json, yarn.lock, pnpm-lock.yaml, poetry.lock, go.sum) и устанавливайте зависимости в CI через npm ci, чтобы сборки были воспроизводимыми, а новый upstream-релиз не мог проскочить без проверки.

  • Сканируйте постоянно: npm audit, pip-audit, bundler-audit, GitHub Dependabot или Renovate для обновлений и сканер контейнеров, например Trivy или Grype, для уровня ОС.

  • Откладывайте обновления, не связанные с безопасностью, на несколько дней (minimumReleaseAge в Renovate), чтобы отравленный релиз, как правило, успели отозвать до того, как вы его примете, но патчи безопасности применяйте немедленно.

  • Фиксируйте сторонние actions и скрипты на SHA коммита в CI и используйте Subresource Integrity (integrity="sha384-...") для каждого скрипта, который загружаете с публичного CDN.

  • Давайте CI минимальные привилегии: токены только для чтения там, где это возможно, короткоживущие учётные данные OIDC вместо долгоживущих секретов и права на публикацию только у задачи релиза.

  • Генерируйте SBOM (CycloneDX или SPDX) при сборке, чтобы ответить на вопрос «нас это затрагивает?» за минуты, когда появится следующая CVE масштаба Log4Shell.

bash
# Reproducible install + audit in CI
npm ci --ignore-scripts
npm audit --audit-level=high

# Pin a GitHub Action to a commit, not a floating tag
# uses: actions/checkout@v4                 <- can change underneath you
# uses: actions/checkout@<full-commit-sha>  # v4.2.2

# Subresource Integrity for a CDN script (hash from: openssl dgst -sha384 -binary lib.min.js | openssl base64 -A)
<script src="https://cdn.example.com/lib.min.js"
        integrity="sha384-<base64-hash>"
        crossorigin="anonymous"></script>

Совет

npm ci --ignore-scripts блокирует скрипты, выполняемые при установке, через которые запускается большинство вредоносных npm-пакетов; затем снова включите скрипты только для тех немногих пакетов, которым действительно нужен этап сборки.

Если у вас WordPress или другая CMS, те же правила относятся к плагинам и темам — именно с них начинается большинство взломов CMS. Обновляйте ядро и все плагины, удаляйте неиспользуемые и проверьте, что сканер может узнать о ваших версиях, с помощью инструмента Определение CMS.

Уровень 6: защита сервера (порты, патчи, секреты, резервные копии)

Уровень приложения ничего не значит, если сервер под ним принимает вход по паролю через SSH, держит базу данных на публичном порту или не обновлялся с момента установки. Лучшие практики для серверов скучны — и именно через их отсутствие проникают программы-вымогатели.

Закройте все порты, которые вы не обслуживаете

Публичному веб-серверу нужны открытые порты 80 и 443 и SSH только с вашего диапазона IP-адресов. Базы данных (3306, 5432, 27017), Redis (6379), Elasticsearch (9200), админ-панели и эндпоинты метрик должны слушать только localhost или частную сеть. После каждого изменения проверяйте сервер снаружи с помощью проверки портов: именно так его видит атакующий, а группы безопасности в облаке легко истолковать неправильно.

bash
# Ubuntu: default-deny firewall, allow only web + SSH from your office range
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw allow from 203.0.113.0/24 to any port 22 proto tcp
sudo ufw enable

# SSH: keys only, no root password login
sudo sed -i 's/^#\?PasswordAuthentication.*/PasswordAuthentication no/' /etc/ssh/sshd_config
sudo sed -i 's/^#\?PermitRootLogin.*/PermitRootLogin prohibit-password/' /etc/ssh/sshd_config
sudo systemctl reload ssh

Патчи по расписанию, секреты — вне кода

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

Секретам (паролям от баз данных, API-ключам, ключам подписи) не место в репозитории, в слое Docker-образа или в клиентском JavaScript. Загружайте их из переменных окружения, которые подставляются при деплое, или из менеджера секретов, меняйте их, когда уходит кто-то, у кого был доступ, и сканируйте историю репозитория инструментом вроде gitleaks: однажды закоммиченный ключ скомпрометирован навсегда, даже если коммит удалён.

Внимание

Всё с префиксом NEXT_PUBLIC_, VITE_ или REACT_APP_ попадает в бандл для браузера и по определению публично. Сторонние API-ключи прячьте за собственным серверным маршрутом. В нашем руководстве по тестированию публичного API-эндпоинта показано, как проверить, что на самом деле раскрывает ваш фронтенд.

Резервные копии, которые переживут вымогателя, и CDN перед сайтом

Следуйте правилу 3-2-1: три копии на двух разных носителях, одна — за пределами площадки, причём хотя бы одна копия должна быть неизменяемой или офлайн, чтобы вымогатель, добравшийся до сервера, не смог зашифровать и резервные копии. Шифруйте резервные копии, включайте в них базу данных и каталог загрузок и, что особенно важно, регулярно проверяйте восстановление. Резервная копия, из которой никто ни разу не восстанавливался, — это надежда, а не план. От времени восстановления зависит, станет ли инцидент простоем или концом компании.

Поставьте перед исходным сервером CDN или WAF (Cloudflare, Fastly, AWS CloudFront с WAF или аналог у вашего хостинга). Он поглощает объёмные DDoS-атаки, применяет управляемые правила против распространённых инъекций и вредоносных ботов, скрывает IP-адрес исходного сервера и даёт место, где можно ограничивать частоту запросов и задавать гео-правила, не трогая приложение. Затем настройте файрвол исходного сервера так, чтобы напрямую к порту 443 могли обращаться только IP-диапазоны CDN, иначе атакующие просто обойдут его. Проверка хостинга показывает, раскрыт ли реальный исходный сервер сайта за его CDN.

Аутентификация почты: SPF, DKIM и DMARC

Веб-безопасность включает и почту, через которую уходят сбросы паролей, счета и ответы поддержки. Без SPF, DKIM и DMARC кто угодно может отправлять письма от имени billing@yourdomain.com, а с февраля 2024 года Google и Yahoo требуют все три от массовых отправителей. Весь набор — это три TXT-записи в DNS:

dns
yourdomain.com.                    TXT  "v=spf1 include:_spf.google.com -all"
google._domainkey.yourdomain.com.  TXT  "v=DKIM1; k=rsa; p=MIIBIjANBgkq..."
_dmarc.yourdomain.com.             TXT  "v=DMARC1; p=reject; rua=mailto:dmarc@yourdomain.com; adkim=s; aspf=s"

Заметка

DMARC p=reject — это ещё и защита бренда: только она не даёт фишинговой рассылке поставить ваш точный домен в поле From. Агрегированные отчёты (rua=) показывают, кто пытается это сделать.

Начните DMARC с p=none, чтобы собирать отчёты, затем перейдите на p=quarantine, а потом на p=reject, когда каждый легитимный отправитель (маркетинговая платформа, хелпдеск, CRM) будет проходить проверку выравнивания (alignment). Добавьте записи MTA-STS и TLS-RPT, чтобы принудительно шифровать доставку на ваши почтовые серверы, и опубликуйте null MX (MX 0 .) на доменах, которые никогда не отправляют почту, чтобы их вообще нельзя было подделать. Проверьте каждую запись с помощью инструментов Проверка SPF-записи, Проверка DKIM и Проверка DMARC, а если упала доставляемость, проверьте свои IP-адреса отправки по чёрным спискам через проверку IP в чёрных списках.

Логируйте, мониторьте и готовьтесь к взлому

Две из десяти категорий OWASP 2025 посвящены тому, что происходит после ошибки: Security Logging and Alerting Failures (A09, сбои логирования и оповещений) и новая Mishandling of Exceptional Conditions (A10, неправильная обработка исключительных ситуаций). Типичный взлом по-прежнему остаётся незамеченным месяцами, потому что доказательства так и не были записаны — или были записаны, но никто их не смотрел.

  • Логируйте события безопасности с контекстом: каждый успешный и неудачный вход, изменения MFA, сбросы паролей, изменения прав, отказы в доступе, ошибки валидации ввода и действия администраторов — с меткой времени, ID пользователя, IP-адресом источника и user agent.

  • Никогда не логируйте секреты: пароли, сессионные токены, полные номера карт, API-ключи. Маскируйте их на уровне логирования, а не в каждом месте вызова.

  • Отправляйте логи за пределы сервера в централизованное хранилище (CloudWatch, Loki, Elastic, SIEM) со сроком хранения не менее 90 дней, чтобы атакующий с правами root не мог замести следы.

  • Настраивайте оповещения на шаблоны, а не на отдельные события: 50 неудачных входов за минуту, всплеск ответов 403 в одной сессии, новый администратор, созданный в нерабочее время, сертификат для вашего домена, который вы не запрашивали.

  • Закрывайтесь при сбое (fail closed): если зависимая проверка (сервис аутентификации, rate limiter, WAF) завершается ошибкой, отклоняйте запрос. Категория A10 существует потому, что очень многие системы предоставляют доступ, когда проверка, которая должна была его заблокировать, выбрасывает исключение.

  • Мониторьте снаружи: доступность, срок действия сертификатов, изменения DNS, попадание в чёрные списки и регрессии заголовков. Проверка здоровья домена объединяет проверки DNS, SSL, аутентификации почты и заголовков в одну оценку, которую можно перезапускать после каждого деплоя.

Напишите план реагирования на инциденты заранее

Заранее решите, кто дежурит, как сменить все учётные данные, как перевести сайт в режим только для чтения, где лежат чистые резервные копии и каких регуляторов или клиентов нужно уведомить и в течение скольких часов (72 часа по GDPR). Раз в год проводите штабные учения (tabletop exercise). Команды с отрепетированным планом восстанавливаются за дни; команды без него импровизируют неделями.

Совет

Добавьте файл security.txt по адресу /.well-known/security.txt (RFC 9116) с контактным адресом и PGP-ключом. Исследователи, нашедшие уязвимость на вашем сайте, воспользуются им; иначе они могут опубликовать её открыто.

Проверяйте: сканеры, пентесты и непрерывный контроль

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

ПроверкаИнструментКак часто
Конфигурация TLS, цепочка, срок действияПроверка SSL-сертификата, SSL Labs, testssl.shПосле каждого изменения сертификата или сервера; срок действия — ежедневно
Заголовки безопасности и CSPПроверка HTTP-заголовков, MDN HTTP ObservatoryПосле каждого деплоя (добавьте в CI)
Открытые портыПроверка портов, nmapПосле каждого изменения файрвола или облачных настроек
DNS, DNSSEC, аутентификация почтыПроверка здоровья домена, Проверка DMARCЕжемесячно и после любого изменения DNS
Устаревшие поддоменыПоиск поддоменовЕжеквартально и при каждом выводе сервиса из эксплуатации
Зависимости с известными уязвимостямиnpm audit, Dependabot, TrivyПри каждой сборке
Уязвимости на уровне кода (SAST)Semgrep, CodeQLВ каждом pull request
Уязвимости работающего веб-приложения (DAST)OWASP ZAP, NucleiЕженедельно на staging
Авторизация и бизнес-логикаРучной пентест или программа bug bountyЕжегодно и после выпуска крупных функций

Сканеры хорошо находят инъекции, проблемы с заголовками и устаревшие компоненты и плохо — ошибки авторизации и бизнес-логики, поэтому заложите в бюджет хотя бы один ручной тест в год для всего, что работает с деньгами или персональными данными. Исправляйте в порядке доступности для атаки: первым делом — всё, что может эксплуатировать неаутентифицированный пользователь из интернета.

Чек-лист безопасности сайта

Скопируйте его в README проекта или в трекер задач. Каждая строка — одна из практик выше, сформулированная так, чтобы её можно было отметить как выполненную или невыполненную; последний столбец — доказательство.

УровеньПрактикаГотово, когда
ДоменRegistrar lock и MFA в аккаунте регистратора; автопродление включеноWHOIS показывает clientTransferProhibited; до окончания регистрации больше 12 месяцев
DNSЗона подписана DNSSEC; запись CAA перечисляет только ваши центры сертификацииdig +dnssec возвращает RRSIG; DS-запись есть в родительской зоне
DNSНет «висячих» записей CNAME или AКаждое имя хоста из поиска поддоменов указывает на ресурс, который вы контролируете
TLSТолько TLS 1.2+, предпочтительно TLS 1.3, отдаётся полная цепочкаПроверка SSL-сертификата: цепочка полная, TLS 1.0/1.1 отклоняются
TLSHSTS с max-age на год, includeSubDomains, в preload-спискеДомен есть в списке hstspreload.org
TLSПродление автоматизировано через ACME; срок действия отслеживаетсяcertbot renew --dry-run проходит; оповещение настроено за 14 дней
ЗаголовкиCSP (на основе nonce), frame-ancestors, nosniff, Referrer-Policy, Permissions-PolicyПроверка HTTP-заголовков: оценка A
АутентификацияХеширование Argon2id или bcrypt; правила паролей NIST; проверка по базам утечекОдин хеш вычисляется 100–250 мс; нет правил состава
АутентификацияMFA доступна всем и обязательна для администраторов; поддерживаются passkeysВход администратора невозможен без второго фактора
АутентификацияДля эндпоинтов входа, сброса пароля и MFA действует rate limiting по IP и по учётной записиШестая попытка за минуту возвращает 429
СессииCookie с префиксом __Host- и флагами Secure, HttpOnly, SameSite; ID меняется при входеАтрибуты cookie видны в DevTools; старая сессия недействительна после входа
Ввод данныхПараметризованные запросы везде; вывод кодируется по контексту; загрузки проверяются по содержимомуПоиск по коду не находит запросов, собранных из строк; XSS-пейлоады отображаются как текст
Контроль доступаМаршрутизация с запретом по умолчанию; проверка владения для каждого объекта; строгий CORSПовтор запросов с ID другого пользователя возвращает 404 или 403
ЗависимостиLockfile в репозитории; npm ci; аудит в CI; actions зафиксированы на SHA; SRI для скриптов с CDNСборка падает при CVE высокой критичности
СерверПублично открыты только 80 и 443; SSH только по ключам; автоматические обновления безопасности; секреты в env или vaultПроверка портов показывает, что 22, 3306 и 6379 закрыты из интернета
Резервные копии3-2-1 с одной неизменяемой копией; восстановление провереноПоследняя успешная проверка восстановления — не старше 90 дней
ПочтаSPF -all, DKIM, DMARC p=reject, MTA-STSПроверка DMARC пройдена; агрегированные отчёты приходят
МониторингСобытия аутентификации и авторизации логируются централизованно; оповещения на шаблоны; внешний мониторинг доступности, сертификатов и DNSТестовое оповещение отправлено и получено
РеагированиеПисьменный план реагирования на инциденты; опубликован security.txt; проведены штабные ученияПлан пересматривался в течение последних 12 месяцев

Как это соотносится с OWASP Top 10:2025

OWASP Top 10 — самый цитируемый список рисков безопасности веб-приложений; в редакции 2025 года порядок изменился и появились две новые категории. Если клиент, аудитор или стандарт соответствия спросит, как вы закрываете эти риски, вот таблица соответствия практикам из этого руководства:

OWASP Top 10:2025Практики в этом руководстве
A01 Broken Access Control (нарушение контроля доступа)Запрет по умолчанию, проверки для каждого объекта, строгий CORS, закрытые админ-панели
A02 Security Misconfiguration (небезопасная конфигурация)Заголовки безопасности, HSTS, закрытые порты, удалённые заголовки с версиями, отключённый листинг каталогов
A03 Software Supply Chain Failures (сбои цепочки поставок ПО) — новаяLockfile, аудит, зафиксированные actions, SRI, SBOM, CI с минимальными привилегиями
A04 Cryptographic Failures (криптографические ошибки)TLS 1.2+ и 1.3, HSTS, Argon2id, управление секретами, шифрование резервных копий
A05 Injection (инъекции)Параметризованные запросы, кодирование вывода, CSP, проверка загружаемых файлов
A06 Insecure Design (небезопасное проектирование)Модель угроз для каждого уровня, закрытие при сбое по умолчанию, rate limiting на этапе проектирования
A07 Authentication Failures (ошибки аутентификации)Правила паролей NIST, проверка по базам утечек, MFA и passkeys, ротация сессий
A08 Software or Data Integrity Failures (нарушение целостности ПО и данных)SRI, подписанные и зафиксированные зависимости, безопасная десериализация
A09 Security Logging and Alerting Failures (сбои логирования и оповещений)Централизованное логирование, оповещения на шаблоны, внешний мониторинг
A10 Mishandling of Exceptional Conditions (неправильная обработка исключительных ситуаций) — новаяЗакрытие при сбое, единообразные ответы об ошибках, никаких трассировок стека для пользователей

Заметка

OWASP ASVS (Application Security Verification Standard) превращает тот же материал в пронумерованный чек-лист для аудитов. Уровень ASVS L1 — реалистичная цель для любого публичного сайта; L2 — для всего, что обрабатывает персональные или финансовые данные.

Проверьте заголовки безопасности своего сайта за секунды

Бесплатная проверка HTTP-заголовков от DNS Robot загружает любой URL и оценивает его заголовки безопасности по шкале от A до F: HSTS, Content-Security-Policy, X-Frame-Options, X-Content-Type-Options, Referrer-Policy и Permissions-Policy — с точным найденным значением и списком того, чего не хватает. Без регистрации.

Попробовать проверку HTTP-заголовков

Advertisement

Частые вопросы о безопасности сайта

Переведите сайт на HTTPS с современным TLS и HSTS, отправляйте строгие заголовки безопасности (прежде всего Content Security Policy), хешируйте пароли с Argon2id и защитите вход MFA и rate limiting, используйте параметризованные запросы и кодирование вывода, проверяйте права доступа на сервере для каждого объекта, своевременно обновляйте зависимости и фиксируйте их версии, закройте неиспользуемые порты и централизованно логируйте события безопасности. Начните с защиты домена и DNS, потому что всё остальное зависит от того, контролируете ли вы по-прежнему своё доменное имя.

Связанные инструменты

HTTP Headers CheckSSL Certificate CheckPort CheckerDomain Health CheckerDMARC CheckerSubdomain FinderPassword Strength Tester

Похожие статьи

Что такое цепочка сертификатов SSL? Как это работаетX-Frame-Options Explained: Fix “Refused to Connect” in an iframeОшибка 429 Too Many Requests: причины и способы устраненияWHOIS домена: как узнать владельца и прочитать запись

Содержание

  • Что на самом деле означает безопасность сайта
  • Стек веб-безопасности: шесть уровней защиты
  • Уровень 1: защитите домен и DNS
  • Уровень 2: HTTPS и TLS как положено
  • Уровень 3: HTTP-заголовки безопасности
  • Уровень 4: аутентификация, устойчивая к credential stuffing
  • Сессии, cookie и CSRF
  • Инъекции и XSS: проверяйте ввод, кодируйте вывод
  • Broken Access Control: риск номер один
  • Уровень 5: зависимости и цепочка поставок ПО
  • Уровень 6: защита сервера (порты, патчи, секреты, резервные копии)
  • Аутентификация почты: SPF, DKIM и DMARC
  • Логируйте, мониторьте и готовьтесь к взлому
  • Проверяйте: сканеры, пентесты и непрерывный контроль
  • Чек-лист безопасности сайта
  • Как это соотносится с OWASP Top 10:2025
  • Часто задаваемые вопросы