Чек-лист безопасности веб-приложений для разработчиков
Это практический, готовый к аудиту чек-лист, сопоставленный с уровнями верификации OWASP ASVS 4.0.3 и идентификаторами тестов WSTG, которыми реально пользуется пентестер. Каждый пункт — конкретный контроль, который можно внедрить, увидеть в диффе и протестировать в CI, а не лозунг. Идите сверху вниз; каждый непроставленный флажок считайте открытой находкой.
Аутентификация и управление сессиями
Сбои аутентификации соответствуют OWASP Top 10 A07:2021 и главам ASVS V2 (Authentication) и V3 (Session Management). Цель — сделать кражу учётных данных, brute force и фиксацию сессии структурно невозможными, а не просто затруднёнными. Проверяйте каждый пункт по WSTG-ATHN и WSTG-SESS.
- Храните пароли с памяте-затратной KDF: Argon2id (≥19 MiB, t=2, p=1) либо bcrypt со стоимостью ≥10 / scrypt — никогда MD5, SHA-1 или несолёный SHA-256 (ASVS V2.4).
- Требуйте минимум 12 символов, разрешайте весь диапазон Unicode и пробелы и проверяйте новые пароли по базе утечек (API k-анонимности HIBP) — не навязывайте правила сложности и принудительную ротацию (ASVS V2.1, NIST SP 800-63B).
- Ограничивайте частоту попыток входа с экспоненциальной задержкой на аккаунт и на IP-адрес; возвращайте идентичные ответы и тайминги для верных и неверных логинов, чтобы предотвратить перебор пользователей (WSTG-ATHN-03).
- Генерируйте идентификаторы сессии через CSPRNG (≥128 бит энтропии) и пересоздавайте идентификатор сессии при каждой смене привилегий — входе, выходе и step-up — чтобы устранить session fixation (WSTG-SESS-03).
- Устанавливайте cookie сессии как HttpOnly, Secure и SameSite=Lax или Strict; ограничивайте их префиксом __Host- без явного атрибута Domain (ASVS V3.4).
- Применяйте на стороне сервера и таймаут по бездействию, и абсолютное время жизни сессии; аннулируйте токен сессии на сервере при выходе, а не только на клиенте.
- Предлагайте устойчивый к фишингу MFA — WebAuthn/FIDO2 или TOTP — и никогда SMS как единственный второй фактор; требуйте повторный MFA перед чувствительными действиями (ASVS V2.2, V2.7).
- Делайте токены сброса пароля одноразовыми, короткоживущими (≤1 час), случайными и доставляемыми вне основного канала; аннулируйте все активные сессии при смене пароля (WSTG-ATHN-09).
Контроль доступа и авторизация
Broken Access Control — это A01:2021, риск номер один. Большинство таких багов — логические изъяны, которые не найдёт ни один сканер, поэтому нужны явная серверная проверка и контроль на уровне каждого объекта. Тестируйте по WSTG-ATHZ (IDOR, эскалация привилегий, path traversal).
- Проверяйте авторизацию на сервере для каждого запроса; по умолчанию запрещайте и никогда не полагайтесь на скрытый элемент UI, отключённую кнопку или клиентскую проверку роли как на контроль.
- Проверяйте владение на уровне объекта при каждом доступе — получите ресурс, затем подтвердите, что аутентифицированный субъект вправе действовать с этим конкретным ID — чтобы предотвратить IDOR / BOLA (WSTG-ATHZ-04).
- Используйте непредсказуемые или косвенные ссылки на объекты (UUIDv4 или маппинг на пользователя), но считайте это защитой в глубину, а не заменой проверки владения выше.
- Централизуйте авторизацию в одном слое middleware/политик (например, движок ABAC/RBAC), а не разбрасывайте разрозненные if по контроллерам.
- Блокируйте пути эскалации привилегий: убедитесь, что пользователь не может задать себе роль, tenant_id или флаг is_admin через mass-assignment на эндпоинтах создания/обновления (WSTG-ATHZ-02).
- Применяйте защиту от CSRF на всех изменяющих состояние запросах — синхронизирующий токен либо cookie SameSite плюс валидация Origin/Referer для чувствительных к cross-site действий (WSTG-SESS-05).
- Валидируйте и канонизируйте пути файлов и импортируемые URL, чтобы заблокировать directory traversal (../) и SSRF к внутренним эндпоинтам метаданных вроде 169.254.169.254 (WSTG-ATHZ-01, A10:2021).
Валидация ввода и кодирование вывода
Injection — это A03:2021. Устойчивое решение — разделение кода и данных на каждой границе интерпретатора: SQL, шелл ОС, LDAP, XML и DOM браузера. Валидируйте ввод по намерению, но реальную защиту стройте на контекстном кодировании вывода и параметризации (WSTG-INPV).
- Используйте параметризованные запросы / prepared statements или проверенный ORM для всего доступа к БД; никогда не собирайте SQL конкатенацией строк, а любой динамический идентификатор (таблица/колонка) проверяйте по allowlist (WSTG-INPV-05).
- Валидируйте весь ввод по позитивному allowlist — тип, длину, формат и диапазон — на границе доверия; где возможно, отклоняйте, а не санитизируйте (ASVS V5.1).
- Применяйте контекстное кодирование вывода для защиты от XSS: кодирование HTML-сущностей в теле HTML, кодирование атрибутов в атрибутах и кодирование JavaScript/URL в их контекстах — предпочитайте авто-экранирующие шаблонизаторы (WSTG-CLNT-01).
- Избегайте выполнения команд ОС с пользовательским вводом; если неизбежно — используйте API с массивом аргументов (execFile, а не shell=True) и никогда не пропускайте данные через интерпретатор шелла (WSTG-INPV-12).
- Отключайте разбор внешних сущностей XML (XXE) в каждом парсере XML/SOAP/SVG — задайте FEATURE_SECURE_PROCESSING и запретите DOCTYPE (A05:2021, WSTG-INPV-07).
- Отклоняйте небезопасную десериализацию: никогда не десериализуйте недоверенные данные в произвольные типы; используйте ограниченный схемой формат вроде JSON с явным маппингом полей (A08:2021).
- Внедрите серверный контроль загрузки файлов: проверяйте тип содержимого по magic bytes, ограничивайте размер, храните вне web root и отдавайте с Content-Disposition: attachment.
- Валидируйте цели редиректов по allowlist, чтобы предотвратить open redirect, применяемый в фишинге (WSTG-CLNT-04).
Заголовки безопасности (CSP, HSTS и другие)
Заголовки HTTP-ответов — дешёвая и высокорычажная защита в глубину против XSS, кликджекинга и понижения протокола. Отсутствие заголовков относится к A05:2021 Security Misconfiguration; проверяйте через WSTG-CONF-07 и сканер вроде securityheaders.com или Mozilla Observatory.
- Разверните строгий Content-Security-Policy: предпочитайте script-src на основе nonce или hash с 'strict-dynamic', задайте object-src 'none' и base-uri 'none', избегайте 'unsafe-inline' — выкатывайте сначала через Content-Security-Policy-Report-Only.
- Установите Strict-Transport-Security: max-age=31536000; includeSubDomains; preload и подайте домен в список HSTS preload, чтобы заблокировать SSL-stripping.
- Отправляйте X-Content-Type-Options: nosniff в каждом ответе, чтобы остановить MIME sniffing.
- Предотвращайте кликджекинг через frame-ancestors 'none' (или явный allowlist) в CSP; оставьте X-Frame-Options: DENY как запасной вариант для старых браузеров.
- Задайте Referrer-Policy: strict-origin-when-cross-origin, чтобы не утекали полные URL (и токены в них) к третьим сторонам.
- Ограничьте возможности браузера через Permissions-Policy (например, geolocation=(), camera=(), microphone=()) и установите Cross-Origin-Opener-Policy: same-origin.
- Настраивайте CORS явно: отражайте только проверенные origin, никогда не сочетайте Access-Control-Allow-Origin: * с Allow-Credentials: true и валидируйте заголовок Origin на сервере (WSTG-CLNT-07).
Безопасность зависимостей и цепочки поставок
Уязвимые и устаревшие компоненты — это A06:2021; здесь живут инциденты класса SolarWinds и Log4Shell. Дисциплина в том, чтобы точно знать, что вы поставляете, проверять целостность и патчить по расписанию. Ориентируйтесь на SLSA и NIST SSDF.
- Запускайте автоматический SCA (Dependabot, npm audit, OWASP Dependency-Check, Trivy) в CI и обрывайте сборку при известных эксплуатируемых (из списка KEV) или высокой критичности CVE.
- Фиксируйте зависимости на точных версиях и коммитьте lockfile (package-lock.json, poetry.lock, go.sum), чтобы сборки были воспроизводимыми и верифицировались по хешу.
- Генерируйте и храните SBOM (CycloneDX или SPDX) для каждого релиза, чтобы за минуты после нового CVE ответить на вопрос «затронуты ли мы?».
- Проверяйте транзитивные зависимости и следите за typosquatting / dependency confusion; резервируйте имена внутренних пакетов и настройте registry на приоритет приватного индекса.
- Проверяйте целостность артефактов подписями (Sigstore/cosign) и фиксируйте сторонние GitHub Actions на полный SHA коммита, а не на изменяемый тег.
- Подпишитесь на бюллетени безопасности ключевых фреймворков и задайте SLA — например, критические CVE патчатся за 72 часа, высокие — за 7 дней.
- Удаляйте неиспользуемые зависимости и мёртвые фичи; каждый пакет, который вы не поставляете, — это поверхность атаки, которую вам не нужно защищать.
Управление секретами
Захардкоженные учётные данные — извечная находка (CWE-798) и часть A05:2021. Секреты не должны попадать в исходники, образы и логи; их следует внедрять во время выполнения, ротировать и ограничивать минимальными привилегиями. Проверяйте по ASVS V6 (Stored Cryptography) и V2.10 (учётные данные сервисов).
- Держите секреты вне системы контроля версий; сканируйте репозиторий и всю историю git с помощью gitleaks или trufflehog и внедрите сканер секретов в pre-commit / CI как блокирующий гейт мержа.
- Храните секреты в выделенном менеджере (HashiCorp Vault, AWS Secrets Manager, GCP Secret Manager) или зашифрованном хранилище платформы — внедряйте через окружение или примонтированный том во время выполнения, никогда не запекайте их в образы контейнеров.
- Ротируйте учётные данные по расписанию и немедленно при подозрении на утечку; предпочитайте короткоживущие, динамически выдаваемые учётные данные (dynamic secrets Vault, облачные IAM-роли / OIDC-федерация) долгоживущим статическим ключам.
- Ограничивайте каждый секрет минимальными привилегиями — отдельный пользователь БД на сервис только с нужными грантами — чтобы одна утечка не скомпрометировала всю систему.
- Никогда не логируйте секреты, токены или полные заголовки авторизации; добавьте фильтры редактирования в конвейер логирования и проверьте, что они работают.
- Шифруйте секреты в покое управляемым KMS и держите ключевой материал вне той же границы доверия, что и защищаемые им данные.
Логирование, мониторинг и обнаружение
Сбои логирования и мониторинга безопасности — это A09:2021: нельзя реагировать на то, чего не видишь. Логируйте значимые для безопасности события структурированно и в защищённом от подделки виде и подключайте их к оповещениям. Проверяйте по ASVS V7 и сигнатурам атак, выведенным из WSTG.
- Логируйте все события аутентификации (успех и провал), отказы контроля доступа, отклонения валидации ввода и действия администратора — с указанием кто, что, когда и откуда, в структурированном JSON (ASVS V7.1).
- Никогда не логируйте чувствительные данные — пароли, токены сессий, полные номера карт, секреты — и нейтрализуйте log injection кодированием недоверенных значений (CWE-117).
- Отправляйте логи за пределы хоста в централизованное хранилище только-на-добавление (SIEM), чтобы захвативший машину атакующий не мог стереть следы; храните согласно требованиям комплаенса.
- Оповещайте о сигналах безопасности почти в реальном времени: всплески brute-force, серии отказов авторизации, создание нового админа и известные паттерны атак — с маршрутом on-call.
- Включайте ID корреляции/запроса между сервисами, чтобы инцидент можно было восстановить end-to-end.
- Тестируйте своё обнаружение: проведите атаку (или учение purple team) и убедитесь, что событие действительно поднимает алерт — непротестированное логирование это театр.
- Синхронизируйте часы (NTP) и записывайте метки времени в UTC, чтобы межсистемные таймлайны были надёжны при форензике.
TLS и безопасность транспорта
Cryptographic Failures — это A02:2021. Все данные в передаче должны шифроваться современным, правильно настроенным TLS; валидный сертификат необходим, но недостаточен. Тестируйте через WSTG-CRYP-01, testssl.sh и SSL Labs, целясь в оценку A+.
- Отдавайте всё по HTTPS и перенаправляйте HTTP на HTTPS; вместе с HSTS preload не допускайте отката на plaintext.
- Поддерживайте только TLS 1.2 и TLS 1.3; отключите SSLv3, TLS 1.0 и TLS 1.1 и уберите наборы шифров export/NULL/RC4/3DES (WSTG-CRYP-01).
- Предпочитайте AEAD-наборы шифров (AES-GCM, ChaCha20-Poly1305) и включайте forward secrecy только через обмен ключами ECDHE.
- Используйте сертификаты доверенного CA с ключом RSA ≥2048 бит или ECDSA P-256; автоматизируйте выпуск и продление (ACME/Let's Encrypt), чтобы сертификаты никогда молча не истекали.
- Включите OCSP stapling и рассмотрите DNS-записи CAA, чтобы ограничить, какие CA могут выпускать сертификаты для вашего домена.
- Терминируйте TLS и для внутреннего трафика между сервисами (mTLS где практично) — не считайте внутреннюю сеть доверенной.
- Для нативных/мобильных клиентов рассмотрите certificate pinning и всегда проверяйте полную цепочку и имя хоста — никогда не отключайте проверку «чтобы заработало».
Главное
- ›Проверяйте каждое решение контроля доступа и авторизации на сервере, на уровне объекта — Broken Access Control (A01) это риск номер один, и эти логические изъяны сканер за вас не найдёт.
- ›Побеждайте injection (A03) параметризованными запросами и контекстным кодированием вывода, а не фильтрацией по blocklist.
- ›Разверните строгий CSP на основе nonce плюс HSTS preload, X-Content-Type-Options и frame-ancestors — дешёвые заголовки, притупляющие XSS, понижение протокола и кликджекинг.
- ›Держите секреты вне кода, ротируйте их и предпочитайте короткоживущие динамически выдаваемые учётные данные статическим ключам.
- ›Нельзя реагировать на то, что не логируешь: структурированное, защищённое от подделки логирование безопасности с протестированными оповещениями закрывает A09.
- ›Сопоставляйте работу с уровнями OWASP ASVS и идентификаторами тестов WSTG, чтобы «безопасно» стало проверяемым, а не декларативным.
Частые вопросы
В чём разница между OWASP ASVS и OWASP Top 10?+
Top 10 — это документ для повышения осведомлённости, ранжирующий десять наиболее критичных категорий риска (например, A01 Broken Access Control). ASVS — детальный тестируемый стандарт верификации с сотнями конкретных требований по трём уровням доверия (L1–L3). Используйте Top 10 для коммуникации риска, а ASVS как реальный инженерный чек-лист.
Какой уровень ASVS должно достигать моё приложение?+
Уровень 1 — минимум для любого приложения и по большей части проверяем методами black-box. Уровень 2 — стандарт для приложений с чувствительными данными; большинству бизнес-приложений следует целиться в L2. Уровень 3 — для систем наивысшего доверия (платежи, здоровье, критическая инфраструктура) и требует глубокого ревью дизайна.
Может ли чек-лист заменить пентест?+
Нет. Чек-лист предотвращает известные классы дефектов и готовит вас к аудиту, но не найдёт изъяны бизнес-логики, цепочки эксплойтов и специфичные для среды ошибки конфигурации. Используйте чек-лист для непрерывного хардининга в CI, а пентест — для независимой проверки того, что контроли реально выдерживают атаку.
Как часто запускать сканирование зависимостей?+
Непрерывно. Встройте SCA (Dependabot, Trivy, OWASP Dependency-Check) в каждый прогон CI, чтобы новый код проверялся при коммите, и запускайте плановые сканы основных веток, чтобы свежераскрытые CVE в уже смерженных зависимостях ловились даже когда никто не деплоит.
Хотите проверить этот чек-лист на своём работающем приложении? MonMyIP проводит структурированную оценку на базе ASVS/WSTG и выдаёт приоритизированный отчёт по устранению с доказательной базой. Закажите пентест веб-приложения с определённым скоупом.