Skip to content
Назад к блогу
Безопасность

Основы веб-безопасности: хеширование, валидация и аутентификация

Базовые практики веб-безопасности: bcrypt против Argon2, защита от XSS и SQL-инъекций, JWT, заголовки CSP и MFA — с примерами на JavaScript.

12 мин чтения

Основы веб-безопасности для разработчиков

Веб-безопасность не опциональна. С ростом числа кибератак разработчики обязаны встраивать защиту в каждый слой приложения. Это руководство собирает базовые практики, которые стоит внедрить уже сегодня.

Безопасность паролей

Никогда не храните пароли в открытом виде

Хеширование паролей выполняйте современными алгоритмами: bcrypt, Argon2 или scrypt. Они спроектированы намеренно медленными — это делает атаки полным перебором экономически неэффективными.

// Хорошо: используем bcrypt
const bcrypt = require('bcrypt');
const hash = await bcrypt.hash(password, 12);

Сравнение алгоритмов хеширования

Не все алгоритмы хеширования равнозначны. Выбор зависит от модели угроз и сценария применения:

АлгоритмРазмер выходаСкоростьСценарийСтатус безопасности
MD5128 битОчень быстроКонтрольные суммы, не для безопасностиСломан для безопасности
SHA-256256 битБыстроЦелостность данных, цифровые подписиБезопасен
bcrypt184 битаМедленно (настраиваемо)Хеширование паролейБезопасен
Argon2НастраиваемыйМедленно (настраиваемо)Хеширование паролей (современный)Рекомендуется для новых проектов

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

Энтропия паролей

Стойкость пароля можно измерить математически через энтропию: entropy = log2(charset_size^length). Пароль из 8 строчных букв (алфавит из 26 символов) имеет около 37,6 бит энтропии. Пароль из 16 символов, смешивающий заглавные, строчные, цифры и спецсимволы (95 символов), даёт около 105 бит — экспоненциально сложнее для подбора. Поэтому длина важнее сложности для большинства пользователей. Подробный материал по энтропии паролей и арифметике brute-force см. в руководстве по энтропии паролей.

Используйте менеджер паролей

Рекомендуйте пользователям перейти на менеджер паролей. Пароли, придуманные человеком, склонны следовать предсказуемым паттернам, которые атакующие эксплуатируют словарными атаками. Менеджеры паролей генерируют по-настоящему случайные строки и устраняют переиспользование пароля между сервисами — один из самых распространённых векторов credential-stuffing атак.

Используйте достаточное число раундов соли

Раунды соли определяют вычислительную стоимость. Чем больше — тем безопаснее, но медленнее. 10–12 раундов — разумный баланс для большинства приложений.

Валидация ввода

Проверяйте на клиенте и на сервере

Клиентская валидация улучшает UX, но серверная валидация необходима для безопасности. Никогда не доверяйте вводу клиента.

Очищайте весь пользовательский ввод

Защититесь от инъекций, очищая ввод:

  • Используйте параметризованные запросы для SQL
  • Экранируйте HTML-вывод для защиты от XSS
  • Строго валидируйте загружаемые файлы

Конкретные примеры атак

Понимание реальных атак помогает от них защищаться. Представим форму комментария, которая рендерит пользовательский ввод напрямую в HTML. Атакующий отправляет:

<script>alert('xss')</script>

Если приложение рендерит это без экранирования, скрипт выполняется в браузере каждого посетителя — крадёт cookie, перенаправляет пользователей или внедряет кейлогеры. Решение: всегда кодировать вывод в зависимости от контекста. Используйте библиотеки вроде DOMPurify для очистки HTML.

SQL-инъекция не менее опасна. В форме входа атакующий вводит в поле имени:

' OR 1=1 --

Если запрос строится конкатенацией строк ("SELECT * FROM users WHERE username='" + input + "'"), это полностью обходит аутентификацию. -- комментирует остаток запроса. Решение: всегда используйте параметризованные запросы (также известные как prepared statements). Любая серьёзная библиотека для работы с БД их поддерживает:

// НЕПРАВИЛЬНО: конкатенация строк
db.query(`SELECT * FROM users WHERE username='${input}'`);

// ПРАВИЛЬНО: параметризованный запрос
db.query('SELECT * FROM users WHERE username = $1', [input]);

Content Security Policy (CSP)

В качестве защиты в глубину разверните заголовки Content Security Policy. CSP сообщает браузеру, какие источники контента доверенные, фактически блокируя инлайн-скрипты и загрузку неавторизованных ресурсов. Даже если в коде существует уязвимость XSS, строгая CSP может предотвратить выполнение внедрённого скрипта. Начните с Content-Security-Policy: default-src 'self' и постепенно добавляйте исключения.

Хеш-функции

Выбор подходящего хеша

Разные сценарии требуют разных хеш-функций:

СценарийРекомендуется
Паролиbcrypt, Argon2
ЦелостностьSHA-256
Контрольные суммыSHA-256, MD5 (вне безопасности)
Быстрое хешированиеBLAKE3

Выход хеша и коллизии

MD5 выдаёт 128-битный (32 hex-символа) хеш, тогда как SHA-256 даёт 256 бит (64 hex-символа). Эта разница важна: больший выход означает экспоненциально больше возможных значений хеша, что делает коллизии гораздо менее вероятными. Коллизия — это когда два разных входа дают один и тот же хеш; атакующий, способный изготавливать коллизии, может подделывать цифровые подписи или подменять верифицированные данные.

Коллизии MD5 генерируются за секунды на современном железе. SHA-256 остаётся стойким к коллизиям — известных практических атак нет. Поэтому правильный алгоритм для правильного контекста критичен:

  • Контрольные суммы и дедупликация: MD5 приемлем, когда безопасность не требуется
  • Целостность данных и подписи: SHA-256 даёт сильную стойкость к коллизиям
  • Хранение паролей: bcrypt или Argon2 — добавляют соль и намеренную медлительность

HMAC для аутентификации сообщений

Когда нужно проверить и целостность, и подлинность сообщения, применяйте HMAC (Hash-based Message Authentication Code). HMAC объединяет хеш-функцию с секретным ключом — только стороны, знающие ключ, могут сгенерировать или проверить тег. Это обязательно для аутентификации API, верификации webhook и безопасной генерации токенов.

Никогда не используйте MD5 или SHA-1 для безопасности

MD5 и SHA-1 сломаны в контексте безопасности. Применяйте SHA-256 или SHA-3 для криптографического хеширования.

HTTPS повсюду

Что на самом деле делает TLS

TLS (Transport Layer Security) даёт три критические защиты: шифрование в пути (предотвращает прослушивание), аутентификация сервера (доказывает, что вы общаетесь с настоящим сервером, а не с самозванцем) и целостность данных (детектирует любые подмены при передаче). Без TLS любые данные между пользователями и сервером — пароли, токены, личная информация — идут открытым текстом.

Всегда используйте TLS

  • Получайте сертификаты от доверенных CA (Let’s Encrypt бесплатен и полностью автоматизирован)
  • Перенаправляйте HTTP на HTTPS
  • Используйте заголовки HSTS
  • Поддерживайте версии TLS актуальными

HSTS и mixed content

Заголовок HTTP Strict Transport Security (HSTS) говорит браузерам соединяться только по HTTPS, даже если пользователь набрал http://. Установите Strict-Transport-Security: max-age=31536000; includeSubDomains, чтобы закрепить это на год по всем поддоменам. Это блокирует атаки SSL stripping, при которых атакующий понижает соединение до HTTP.

Следите за предупреждениями mixed content: если HTTPS-страница загружает изображения, скрипты или стили по HTTP, браузеры заблокируют их или выдадут предупреждение. Проверьте страницы на захардкоженные http:// URL и используйте протокол-относительные пути или принудительный HTTPS для всех ресурсов.

Аутентификация

Внедрите rate limiting

Защититесь от brute-force с помощью rate limiting:

  • Ограничьте число попыток входа на IP
  • Добавляйте задержки после неудачных попыток
  • Применяйте CAPTCHA при подозрительной активности

Основы аутентификации через JWT

JSON Web Token (JWT) предоставляет stateless-механизм аутентификации структуры header.payload.signature. Сервер подписывает токен секретным ключом, а клиенты включают его в последующие запросы. Поскольку токен содержит claim-ы пользователя, серверу не нужно искать состояние сессии при каждом запросе — это делает JWT хорошим выбором для распределённых систем и микросервисов.

Всегда задавайте короткие сроки действия для access-токенов (например, 15 минут) и используйте refresh-токены для получения новых access-токенов. Храните refresh-токены безопасно (в httpOnly-cookie, а не в localStorage) и реализуйте ротацию, чтобы каждый refresh-токен можно было использовать только один раз.

Многофакторная аутентификация (MFA)

MFA уже не опциональна для любого серьёзного приложения. Требование второго фактора — TOTP-кодов (Google Authenticator), аппаратных ключей (YubiKey) или push-уведомлений — резко снижает последствия компрометации пароля. Даже если атакующий получил валидные учётные данные, без второго фактора он не пройдёт.

Защита от session fixation

Атаки session fixation возникают, когда атакующий заранее устанавливает известный ему session ID до того, как пользователь аутентифицируется. После входа атакующий использует тот же session ID для угона аутентифицированной сессии. Защита: всегда регенерируйте session ID после успешной аутентификации и инвалидируйте старый.

Безопасное управление сессиями

  • Генерируйте криптографически случайные session ID
  • Устанавливайте флаги secure и httpOnly на cookie
  • Реализуйте таймаут сессии
  • Инвалидируйте сессию при выходе

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

Развёртывание правильных HTTP-заголовков — один из самых эффективных и низкотрудозатратных способов укрепить приложение. Краткий справочник по основным заголовкам безопасности:

ЗаголовокНазначениеПример значения
Content-Security-PolicyЗащита от XSS и инъекции данныхdefault-src 'self'
Strict-Transport-SecurityПринудительный HTTPSmax-age=31536000; includeSubDomains
X-Content-Type-OptionsЗащита от MIME-sniffingnosniff
X-Frame-OptionsЗащита от clickjackingDENY
Referrer-PolicyКонтроль информации в Refererstrict-origin-when-cross-origin

Заголовки задаются на уровне веб-сервера (Nginx, Apache), на уровне CDN/edge (Cloudflare, Vercel) или внутри фреймворка приложения. Проверьте заголовки на securityheaders.com. Цель — рейтинг A+; большинство этих заголовков занимают одну строку конфигурации и ничего не стоят при развёртывании.

Используйте наши инструменты безопасности

Изучите наши инструменты безопасности, чтобы упростить разработку:

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

Часто задаваемые вопросы

Какая самая распространённая уязвимость веб-безопасности?

Cross-Site Scripting (XSS) остаётся самой частой уязвимостью веба по данным OWASP. Она возникает, когда приложения включают непроверенные данные в веб-страницы без должной валидации. Защититесь от XSS, очищая весь пользовательский ввод, используя заголовки Content Security Policy и кодируя вывод в зависимости от контекста (HTML, JavaScript, URL или CSS).

Безопасен ли MD5 для хеширования паролей?

Нет — MD5 никогда не следует использовать для хеширования паролей. Он вычисляется быстро, что делает его уязвимым к brute-force и атакам по радужным таблицам. Современные GPU вычисляют миллиарды MD5-хешей в секунду. Применяйте bcrypt, scrypt или Argon2 — они намеренно медленные и включают встроенное соление для противостояния атакам.

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

Минимум 12 символов рекомендуется, но 16+ символов даёт значительно более сильную защиту. Длина важнее сложности — 20-символьная фраза вроде «correct-horse-battery-staple» сильнее короткого сложного пароля «P@ss1!». Включайте многофакторную аутентификацию (MFA) независимо от длины пароля для критических аккаунтов.

Чем отличаются шифрование и хеширование?

Шифрование обратимо — данные можно расшифровать обратно с помощью ключа. Хеширование одностороннее — восстановить исходные данные из хеша нельзя. Используйте шифрование для данных, которые нужно извлекать (например, хранимые пользовательские данные), а хеширование — для данных, которые достаточно сверять (пароли и контрольные суммы).

Стоит ли реализовывать собственную систему аутентификации?

Нет — построение аутентификации с нуля рискованно и подвержено ошибкам. Используйте проверенные временем фреймворки и сервисы: Auth0, Firebase Auth или Supabase Auth. Они берут на себя хеширование паролей, управление сессиями, ротацию токенов, MFA и защиту от brute-force. Сосредоточьте время разработки на уникальных функциях вашего приложения.

Заключение

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

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

Все статьи