Шифрование данных в веб-приложении: как делать правильно
Шифрование в веб-приложении защищает не все данные и не от всех атак. Разбираем, что шифровать, почему пароли нельзя «зашифровать», где хранить ключи и какие ошибки превращают защиту в декорацию.

Сначала определите, от кого вы защищаете данные
Шифрование не спасёт приложение, если ключ лежит рядом с базой, пароль пишется в лог, а резервная копия хранится в открытом виде. Правильная схема начинается не с выбора алгоритма, а с ответа на вопрос: кто атакующий и какой доступ он уже получил.
Для веб-приложения обычно нужно решить четыре разные задачи:
- защитить трафик между браузером, API и внутренними сервисами;
- защитить данные на диске, в базе и резервных копиях;
- хранить пароли так, чтобы их нельзя было восстановить;
- не допустить утечки ключей через исходный код, логи и переменные окружения.
Эта статья ориентирована на приложения, работающие через TLS 1.2 или TLS 1.3, и современные криптографические библиотеки с поддержкой AEAD-режимов. Конкретный вызов зависит от языка и библиотеки, поэтому перед реализацией сверяйте API с документацией используемой версии.
Что именно шифровать
Не все секреты требуют одного подхода. Если данные должны быть восстановлены приложением, нужна обратимая схема шифрования. Если нужно только проверить пароль, обратимость будет уязвимостью: пароль хранят не зашифрованным, а в виде медленного хеша.
| Данные | Подход | Зачем |
|---|---|---|
| Пароли пользователей | Адаптивное хеширование: Argon2id, scrypt или bcrypt | Проверить пароль без хранения исходного значения |
| Платёжные и персональные поля | Аутентифицированное шифрование на уровне приложения или СУБД | Скрыть содержимое даже при чтении дампа |
| Трафик браузер — сервер | HTTPS с корректной настройкой TLS | Защитить данные в пути |
| Резервные копии | Шифрование на стороне хранилища плюс контроль доступа | Снизить ущерб от утечки архива |
| Токены сессий | Случайные непрозрачные значения, короткий срок жизни, безопасное хранение | Не раскрывать данные и ограничить последствия кражи |
Хеширование[1] — одностороннее преобразование: исходное значение не восстанавливают, а сравнивают результат с новым хешем. Это не разновидность шифрования и не замена ему.
Главный тест схемы простой: если злоумышленник получил дамп базы, сможет ли он сразу прочитать поля или восстановить ключи из соседней таблицы и конфигурации.
Шифруйте данные с аутентификацией
Для новых функций выбирайте AEAD — authenticated encryption with associated data. Такие режимы не только скрывают содержимое, но и проверяют, что шифротекст не изменили. На практике обычно используют AES-GCM или ChaCha20-Poly1305, если их предоставляет актуальная библиотека вашего языка.
К каждому зашифрованному значению нужны как минимум:
- алгоритм и версия формата, если они не заданы конфигурацией;
- идентификатор ключа, которым выполнено шифрование;
- случайный nonce или IV, созданный криптографическим генератором;
- сам шифротекст и тег аутентификации;
- неизменяемые метаданные — например, тип записи или идентификатор пользователя — в качестве associated data, если библиотека это поддерживает.
Nonce нельзя выбирать счётчиком, временем, идентификатором пользователя или обычным генератором случайных чисел. Для конкретного режима действуют собственные требования к длине и уникальности. Повтор nonce с одним ключом может разрушить безопасность AES-GCM.
Не проектируйте собственный формат «ключ плюс шифротекст через двоеточие», если у библиотеки уже есть проверенный контейнер. Зафиксируйте формат в документации, добавьте версию и предусмотрите понятную ошибку при повреждении данных. Ошибка расшифровки не должна возвращать частично обработанное значение.
Разделите ключи и данные
Ключ шифрования не должен храниться в той же базе, где лежит шифротекст. Если приложение читает ключ из постоянного файла на том же сервере, компрометация процесса или резервной копии часто превращает шифрование в формальность.
Для серьёзного приложения используйте KMS или HSM, предоставленный облаком или вашей инфраструктурой. Рабочая модель выглядит так: сервис получает доступ к ключу через отдельную роль, шифрует данные, а в базе хранит шифротекст и идентификатор ключа. Сам корневой ключ не экспортируется в приложение.
Envelope encryption
При конвертном шифровании данные шифрует отдельный ключ данных, а KMS шифрует этот ключ. В записи можно хранить зашифрованный ключ данных рядом с шифротекстом: без доступа к KMS он бесполезен.
Такой подход сокращает число обращений к KMS и упрощает ротацию. Но он требует контроля версий: приложение должно понимать, каким ключом расшифровать старые записи, и не должно удалять старый ключ до завершения миграции.
Сравните уровни защиты
| Уровень | Что защищает | Чего не защищает | Цена решения |
|---|---|---|---|
| TLS | Данные между узлами | Базу, логи и данные после расшифровки | Настройка сертификатов, контроль протоколов и доверенных прокси |
| Шифрование диска | Украденный или отключённый диск | Доступ процесса к смонтированной файловой системе | Зависимость от настроек хостинга и управления доступом |
| Шифрование СУБД | Файлы базы и иногда отдельные колонки | Читателя с правами на запросы и приложение с ключом | Зависимость от СУБД, индексации и резервного копирования |
| Шифрование на уровне приложения | Конкретные поля даже при чтении дампа | Данные в памяти и пользователя с правом расшифровки | Сложные миграции, поиск и работа с ключами |
Это не взаимоисключающие варианты. Для production-системы обычно нужны TLS, шифрование дисков и резервных копий, а чувствительные поля дополнительно шифруют на уровне приложения.
Типичные ошибки, которые ломают схему
«Зашифруем всё одним ключом»
Один ключ ускоряет старт, но увеличивает масштаб инцидента. Утечка ключа раскрывает всю историю данных. Разделяйте ключи по окружениям, назначению и иногда по типам данных. Ключи разработки не должны расшифровывать production.
Секрет в репозитории или логе
Переменная окружения лучше строки в коде, но не является полноценным хранилищем секретов: её могут прочитать дампы процесса, отладчик или система сбора логов. Для production используйте secret manager и минимальные права IAM. Никогда не выводите ключи, токены, открытые персональные поля и исходные пароли в лог.
Поиск по зашифрованному полю
Случайное шифрование одного и того же значения даёт разные шифротексты, поэтому обычный поиск по равенству не работает. Не отключайте случайность ради SQL-запроса. Если поиск действительно нужен, отдельно оцените детерминированный индекс, токенизацию или хеш-индекс: каждый из вариантов раскрывает часть информации о совпадениях.
Ротация без плана восстановления
Ротация — это не удаление старого ключа. Сначала создайте новый ключ, начните шифровать им новые записи, затем постепенно перешифруйте старые. После проверки резервных копий и восстановления только тогда ограничивайте доступ к прежнему ключу.
Расшифровка в каждом слое
Если поле расшифровывается в ORM, сериализаторе, логгере и очереди без явной границы, оно легко попадёт в ответ API или трассировку. Определите слой, где допустима расшифровка, и передавайте дальше только минимально необходимое значение.
Проверьте систему до выхода в production
- Составьте список полей и отметьте, какие из них нужно восстановить, а какие достаточно хешировать.
- Опишите угрозы: дамп базы, чтение логов, украденная резервная копия, компрометация приложения и доступ администратора.
- Проверьте, где появляются данные: HTTP-ответы, очереди, временные файлы, метрики, трассировки, аналитика и резервные копии.
- Зафиксируйте формат шифротекста, версию, идентификатор ключа и правила обработки ошибки аутентификации.
- Проведите восстановление из зашифрованной копии на отдельном стенде без ручного копирования ключей.
- Проверьте ротацию: новые записи используют новый ключ, старые читаются, а после миграции старый ключ можно отозвать по плану.
Отдельно измерьте цену операции. Шифрование добавляет CPU-нагрузку, увеличивает размер записи и может убрать индексы по чувствительным полям. Замеры делайте на вашем языке, СУБД, объёме данных и уровне параллельности. Универсальные цифры из чужого проекта здесь мало полезны.
Где подход ломается
Шифрование на уровне приложения не защищает данные от процесса, который уже может вызвать функцию расшифровки. Если атакующий получил права приложения, он может украсть данные через легитимный API, даже не читая базу напрямую. Поэтому шифрование дополняют авторизацией, изоляцией сервисов, ограничением ролей, аудитом и защитой резервных копий.
Нельзя безопасно зашифровать данные, которые должны постоянно участвовать в сортировке, агрегации и полнотекстовом поиске, не раскрывая часть их структуры. Для таких полей сначала определите, действительно ли нужен исходный текст, или достаточно категорий, диапазонов и отдельных обезличенных признаков.
Что делать дальше
Начните не с внедрения библиотеки, а с инвентаризации: какие данные есть, где они появляются и кто должен их видеть. Затем выберите проверенную библиотеку для вашего языка, KMS для production и формат, который можно мигрировать без остановки сервиса.
После внедрения поставьте контрольные проверки в CI и ревью: запрет секретов в репозитории, отсутствие чувствительных полей в логах, обязательный TLS и тест восстановления резервной копии. В production следите не только за ошибками расшифровки, но и за неожиданным ростом обращений к KMS, количеством отказов доступа и появлением новых мест, где данные покидают границу приложения.
[1] Хеш — результат одностороннего криптографического преобразования. Для паролей нужен именно адаптивный хеш с солью и настройками стоимости вычисления, а не быстрый SHA-256.
Инфобез и 152-ФЗ: Аудит политик конфиденциальности, правила сбора cookie.
Спросить за 20 ₽Источники: OWASP Cryptographic Storage Cheat Sheet, RFC 8446: The Transport Layer Security (TLS) Protocol Version 1.3
Частые вопросы
Можно ли хранить ключ шифрования в переменной окружения?
Нужно ли шифровать пароли пользователей?
Достаточно ли HTTPS, чтобы защитить данные?
Что будет, если потерять ключ?
Можно ли искать и сортировать зашифрованные поля?
Нужно ли шифровать резервные копии, если зашифрована база?
Материал носит информационный характер и подготовлен редакцией «Агентуры». Он не является офертой, рекламой или индивидуальной консультацией. Упомянутые продукты, компании и торговые знаки принадлежат их правообладателям. Перед принятием решений, влекущих юридические или финансовые последствия, обратитесь к профильному специалисту.