Содержание
- Краткое содержание
- Введение: почему обычная ошибка может стать проблемой ИБ
- Что такое безопасная обработка ошибок
- Почему ошибки приводят к компрометации персональных данных
- Основные понятия: что нельзя путать
- Как это работает: правильная модель обработки ошибок
- Архитектура безопасной обработки ошибок
- Что можно показывать пользователю, а что нельзя
- Ошибки в API: как использовать RFC 9457 без утечки данных
- Практические примеры настройки
- Сообщения об ошибках и персональные данные в российском контексте
- Типичные ошибки команд разработки и эксплуатации
- Лучшие практики
- Сравнение подходов к обработке ошибок
- Таблица преимуществ и недостатков безопасного error handling
- Рекомендации эксперта
- Чек-лист внедрения
- Практические сценарии: как ошибка превращается в инцидент
- Как тестировать безопасные сообщения об ошибках
- Политика безопасных сообщений об ошибках: пример структуры
- Отчётность для ИБ и руководства
- Как поступают зрелые компании
- FAQ
- Основные выводы
- Источники
Краткое содержание
Сообщение об ошибке должно помогать пользователю понять, что делать дальше, но не должно раскрывать технические детали системы, персональные данные, токены, SQL-запросы, stack trace, внутренние пути, версии компонентов и структуру инфраструктуры. Подробная диагностика должна уходить только в защищённые серверные журналы, SIEM или систему управления инцидентами, а пользователю нужно показывать короткое безопасное сообщение с кодом обращения или correlation ID. Такой подход соответствует рекомендациям OWASP по обработке ошибок, NIST SP 800-53 SI-11 Error Handling и логике защиты от CWE-209 — генерации сообщений об ошибках с чувствительной информацией.
Для российского бизнеса это не просто вопрос «красивого интерфейса». Если ошибка в приложении приводит к раскрытию персональных данных, это может стать инцидентом в контексте 152-ФЗ и потребовать оценки последствий, внутреннего расследования и, при наличии установленных законом признаков, уведомления Роскомнадзора. Поэтому безопасная обработка ошибок должна быть частью Secure SDLC, код-ревью, тестирования, DevOps-практик и регламентов реагирования.
Введение: почему обычная ошибка может стать проблемой ИБ
На первый взгляд сообщение об ошибке кажется мелочью. Пользователь отправил форму, приложение не смогло обработать запрос, сервер вернул текст: «Произошла ошибка». Всё привычно. Но в реальности именно через ошибки приложения часто раскрывают то, что никогда не должно попадать наружу: внутренние пути к файлам, фрагменты SQL-запросов, имена таблиц, версии фреймворков, stack trace, идентификаторы пользователей, телефоны, email-адреса, токены, session ID, ключи API, параметры подключения к базе данных.
Для атакующего такая информация — не просто «технический шум». Это карта местности. По подробной ошибке можно понять, на каком языке написано приложение, какой фреймворк используется, где лежат файлы, какая база данных подключена, какие таблицы и поля есть внутри, как устроена авторизация и какие сервисы общаются между собой. Дальше начинается цепочка: сначала разведка, затем подбор вектора атаки, затем эксплуатация уязвимости.
OWASP прямо относит подробные ошибки, раскрывающие stack trace и версии компонентов, к признакам небезопасной конфигурации. В сценариях OWASP Top 10 A05:2021 Security Misconfiguration описан случай, когда сервер возвращает пользователю детализированные ошибки, из-за чего раскрываются внутренние сведения и версии компонентов. Это может помочь атакующему найти известную уязвимость в конкретном компоненте.
Важно: безопасные сообщения об ошибках — это не попытка «скрыть всё от пользователя» и оставить его один на один с проблемой. Это баланс. Пользователь должен получить понятный ответ: что произошло, можно ли повторить действие, куда обратиться и какой идентификатор ошибки назвать поддержке. А разработчик и аналитик ИБ должны получить подробный технический контекст в защищённых журналах.
Почему это важно: ошибка — один из самых частых каналов непреднамеренного раскрытия данных. Какие риски возникают: компрометация персональных данных, утечка токенов, упрощение SQL-инъекций, подбор учётных записей, раскрытие инфраструктуры. Типичная ошибка: включить debug-режим в production и вернуть пользователю stack trace. Как делают зрелые компании: используют единый error handling layer, correlation ID, маскирование данных, централизованные логи и регулярные проверки DAST/SAST.
Что такое безопасная обработка ошибок
Безопасная обработка ошибок — это подход, при котором приложение корректно реагирует на сбои, возвращает пользователю безопасное и понятное сообщение, а технические детали сохраняет только во внутреннем защищённом контуре. Такой подход должен работать не только для веб-страниц, но и для API, мобильных приложений, микросервисов, внутренних сервисов, интеграций с платёжными системами, CRM, ERP, Госуслугами, 1С и другими системами.
В нормальной архитектуре есть два уровня сообщения об ошибке:
- Публичный уровень — то, что видит пользователь, клиентское приложение или внешний API-потребитель. Здесь не должно быть конфиденциальных данных, внутренней логики, SQL, stack trace, технических путей и лишних идентификаторов.
- Внутренний уровень — то, что попадает в защищённые журналы, систему мониторинга, SIEM, APM, Sentry-подобную систему или тикет поддержки. Здесь может быть диагностическая информация, но она тоже должна проходить фильтрацию: нельзя логировать пароли, токены, полные номера карт, cookie, паспортные данные и другие чувствительные поля.
NIST SP 800-53 SI-11 Error Handling описывает смысл этой практики так: организация должна учитывать структуру и содержание сообщений об ошибках, чтобы они помогали в корректирующих действиях, но не раскрывали информацию, которую можно использовать против системы. MITRE CWE-209 формулирует проблему ещё жёстче: продукт генерирует сообщение об ошибке, содержащее чувствительную информацию о среде, пользователях или связанных данных.
Ключевой принцип простой: пользователю — действие, инженеру — диагностика. Пользователь видит: «Не удалось обработать запрос. Попробуйте позже или обратитесь в поддержку. Код ошибки: ERR-8F2A». Инженер видит в логах: сервис, endpoint, trace ID, версию релиза, exception class, статус зависимого сервиса, время ответа, но без секретов и персональных данных.
Почему ошибки приводят к компрометации персональных данных
Компрометация персональных данных через сообщения об ошибках чаще происходит не как «большой взлом», а как цепочка небольших просчётов. Один разработчик оставил подробный exception в ответе API. Другой не настроил маскирование логов. На тестовом стенде включили debug и забыли закрыть его от интернета. В форме восстановления пароля показывают: «Пользователь с таким email не найден». Каждая ошибка кажется небольшой, но вместе они дают атакующему слишком много информации.
Самые распространённые сценарии:
1. Раскрытие персональных данных прямо в тексте ошибки
Например, API возвращает:
{
"error": "Validation failed for user ivan.petrov@example.ru, phone +7 999 123-45-67, passport 4512 123456"
}
Такое сообщение может попасть в браузер пользователя, мобильное приложение, прокси, CDN, внешнюю интеграцию, логи клиента, скриншоты в поддержку. Если эти данные относятся к другому субъекту ПДн или раскрываются неавторизованному лицу, возникает риск инцидента.
2. User enumeration через ошибки авторизации
Если форма входа сообщает «Такого email нет» или «Пароль неверный для пользователя», злоумышленник может перебрать адреса и понять, какие учётные записи существуют. Для массовых атак это очень полезно: сначала собираются реальные логины, потом запускаются фишинг, credential stuffing или подбор паролей.
Безопаснее отвечать одинаково: «Неверный логин или пароль». Для восстановления доступа — «Если аккаунт существует, мы отправили инструкцию на указанный адрес».
3. Раскрытие внутренней архитектуры
Stack trace может показать фреймворк, классы, названия микросервисов, структуру директорий и внутренние endpoints. SQL-ошибка может раскрыть имена таблиц и колонок. Ошибка подключения к Redis или PostgreSQL может показать имя хоста, порт, схему сети, логин подключения.
Это не всегда персональные данные, но это информация, которая помогает атакующему двигаться дальше. Поэтому её тоже нельзя показывать наружу.
4. Утечка секретов через debug и логи
MITRE CWE-532 описывает отдельную слабость: запись чувствительной информации в журналы. Логи часто хранятся дольше, копируются в SIEM, попадают в бэкапы, доступны подрядчикам, DevOps-команде и дежурным инженерам. Если туда попали пароли, токены, session ID, JWT, API-ключи или персональные данные — утечка может стать намного шире исходного инцидента.
5. Ошибки на стыке систем
Особенно опасны интеграции: CRM ↔ сайт, мобильное приложение ↔ API, интернет-магазин ↔ платёжный шлюз, личный кабинет ↔ 1С. В таких цепочках ошибка одного сервиса часто пробрасывается наружу без фильтрации. В итоге пользователь видит не безопасное сообщение, а внутренний ответ зависимого сервиса.
Практический вывод: сообщение об ошибке надо рассматривать как часть периметра защиты. Оно может быть безопасным интерфейсом, а может стать несанкционированным каналом раскрытия данных.
Основные понятия: что нельзя путать
Перед настройкой политики ошибок полезно договориться о терминах.
| Термин | Что означает | Почему важно |
|---|---|---|
| Error message | Сообщение об ошибке для пользователя или клиента API | Должно быть безопасным и понятным |
| Exception | Техническое исключение в коде | Не должно попадать пользователю в исходном виде |
| Stack trace | Цепочка вызовов в приложении | Раскрывает внутреннюю структуру кода |
| Correlation ID / Trace ID | Уникальный идентификатор события или запроса | Помогает связать обращение пользователя с внутренними логами |
| Sensitive data | Чувствительные данные: ПДн, токены, секреты, финансовые данные | Нельзя показывать наружу и нельзя писать в логи без необходимости |
| PII / ПДн | Данные, относящиеся к физическому лицу | В РФ регулируются 152-ФЗ |
| Debug mode | Режим подробной диагностики | Не должен быть включён в production |
| Problem Details | Стандартный формат описания ошибок HTTP API по RFC 9457 | Помогает унифицировать ошибки API без самодельных форматов |
Важная мысль: безопасное сообщение об ошибке — не обязательно «ничего не объясняющее». Плохой пример: «Ошибка». Хороший пример: «Не удалось сохранить данные. Проверьте обязательные поля или повторите попытку позже. Код обращения: 7F9C-2026». В первом случае пользователю бесполезно, во втором — понятно и безопасно.
Как это работает: правильная модель обработки ошибок
Безопасная схема выглядит так:
- Приложение получает запрос.
- Возникает ошибка: валидация, отказ доступа, недоступность сервиса, исключение в коде.
- Error handler классифицирует ошибку.
- Пользователю возвращается безопасный ответ.
- Внутренние детали сохраняются в защищённый журнал с trace ID.
- SIEM/APM/лог-платформа получает событие.
- При критичных ошибках создаётся инцидент или уведомление дежурной команды.
Это не должно делаться вручную в каждом контроллере. Зрелая практика — единый слой обработки ошибок: middleware, global exception handler, API gateway policy, error page handler на reverse proxy или сервисный interceptor.
Безопасный публичный ответ
Публичный ответ должен включать:
- общий тип проблемы;
- понятное действие для пользователя;
- корректный HTTP-статус;
- безопасный код ошибки или correlation ID;
- ссылку на поддержку или инструкцию, если это уместно.
Он не должен включать:
- stack trace;
- SQL-запросы;
- имена таблиц и колонок;
- внутренние IP, hostnames, service names;
- версии ПО и библиотек;
- токены, cookie, session ID;
- персональные данные;
- полный путь к файлам;
- реальные значения секретных переменных окружения;
- подробности бизнес-логики, которые позволяют обойти контроль.
Внутренний журнал
Внутренний журнал должен быть полезным для расследования, но тоже безопасным. В него можно писать:
- trace ID;
- endpoint;
- HTTP-метод;
- статус;
- класс ошибки;
- service name;
- environment;
- версию релиза;
- user ID в псевдонимизированном виде;
- длительность запроса;
- результат проверки доступа;
- сведения о зависимом сервисе;
- stack trace, если это нужно инженерам и доступ к логам ограничен.
В него нельзя писать без крайней необходимости:
- пароль;
- токен;
- полное значение cookie;
- номер карты;
- паспортные данные;
- полный текст документа пользователя;
- медицинские данные;
- персональные данные третьих лиц;
- приватные ключи;
- secret key, API key, OAuth refresh token.
OWASP Logging Cheat Sheet и OWASP ASVS отдельно подчёркивают: журналы должны помогать расследованию, но не должны становиться новым хранилищем чувствительных данных.
Архитектура безопасной обработки ошибок
В корпоративной среде безопасные сообщения об ошибках строятся не только в коде приложения. Нужна архитектура из нескольких слоёв.
1. Клиентский слой
Фронтенд, мобильное приложение или SPA не должны отображать «как есть» всё, что пришло от сервера. Даже если backend случайно вернул слишком подробный JSON, клиент должен уметь показать безопасное сообщение. Но это не замена серверной защите, а дополнительный уровень.
2. API gateway или reverse proxy
API gateway может нормализовать ответы, скрывать 5xx-детали, подставлять стандартные error pages и добавлять correlation ID. Для высоконагруженных систем это удобно: единая политика ошибок для множества микросервисов.
3. Application error handler
Это главный уровень. Именно приложение понимает контекст: валидация, права доступа, бизнес-правила, интеграции. Здесь нужно превращать внутренние исключения в безопасный public error contract.
4. Централизованное логирование
Логи приложений, reverse proxy, WAF, EDR, IAM, DLP и БД должны собираться централизованно. Но перед отправкой в SIEM нужно настроить маскирование чувствительных полей.
5. SIEM / SOC / APM
SIEM нужен не для того, чтобы хранить все stack trace подряд, а для корреляции событий. Например, серия 401/403, затем 500 на одном endpoint, затем запрос к несуществующему API — возможный признак разведки или fuzzing. APM помогает увидеть техническую причину, но доступ к нему должен быть ограничен.
6. Процесс реагирования
Если ошибка раскрыла ПДн или секреты, это уже не просто баг. Это повод для triage: что раскрыто, кому, за какой период, есть ли доступ третьих лиц, нужно ли уведомлять ответственных, менять токены, проводить расследование и уведомлять Роскомнадзор.
Что можно показывать пользователю, а что нельзя
| Ситуация | Небезопасно | Безопасно |
|---|---|---|
| Ошибка входа | «Email не найден» | «Неверный логин или пароль» |
| Восстановление пароля | «Пользователь ivan@example.ru не существует» | «Если аккаунт существует, инструкция отправлена» |
| 500 ошибка | Stack trace, путь к файлу, имя сервера | «Не удалось выполнить запрос. Код ошибки: ERR-... » |
| SQL ошибка |
ERROR: relation users_pdn does not exist
|
«Не удалось обработать запрос» |
| Ошибка доступа | «Пользователь 459 не имеет роли admin_finance» | «Недостаточно прав для выполнения действия» |
| Ошибка загрузки файла |
/var/www/app/storage/passports/scan.pdf
|
«Файл не прошёл проверку. Проверьте формат и размер» |
| Ошибка оплаты | Номер карты, bank response raw | «Платёж отклонён банком. Используйте другой способ оплаты» |
| API validation | Полный объект пользователя | Список безопасных полей с ошибками без персональных значений |
| Сервис недоступен | IP, hostname, порт, internal service name | «Сервис временно недоступен. Повторите позже» |
| Captcha / rate limit | Подробность антифрод-логики | «Слишком много запросов. Попробуйте позже» |
Главное правило: сообщение должно объяснять следующий шаг, а не внутреннюю причину до уровня реализации.
Ошибки в API: как использовать RFC 9457 без утечки данных
Для REST API полезно использовать стандарт Problem Details for HTTP APIs. Актуальный стандарт — RFC 9457, он заменяет RFC 7807 и описывает единый машинно-читаемый формат ошибок HTTP API. Это удобно, потому что фронтенд, мобильное приложение и внешние интеграции получают предсказуемый формат.
Пример безопасного ответа:
{
"type": "https://example.ru/problems/request-validation",
"title": "Ошибка проверки данных",
"status": 422,
"detail": "Проверьте заполнение обязательных полей.",
"instance": "/support/errors/ERR-20260728-7F9C",
"traceId": "9c7e2b9a-2b47-4b8f-89a5-2d0fb2a6e119"
}
На что обратить внимание:
detailне должен содержать персональные данные;traceIdдолжен быть случайным или псевдослучайным, не последовательным;instanceне должен раскрывать внутренний путь сервера;typeможет вести на публичную документацию по типам ошибок;- validation errors можно показывать по полям, но без повторения чувствительных значений.
Плохой пример:
{
"error": "SQL exception in /var/www/app/UserController.php: SELECT * FROM users WHERE phone='+79991234567'",
"stack": "...",
"db_host": "10.10.1.24"
}
Такой ответ одновременно раскрывает персональные данные, внутреннюю структуру приложения, SQL-логику и сетевую информацию.
Практические примеры настройки
Nginx: безопасная страница для 5xx
server {
listen 443 ssl;
server_name example.ru;
proxy_intercept_errors on;
error_page 500 502 503 504 /50x.html;
location /50x.html {
root /usr/share/nginx/html;
internal;
}
location / {
proxy_pass http://backend;
proxy_set_header X-Request-ID $request_id;
add_header X-Request-ID $request_id always;
}
}
Смысл: пользователь видит стандартную страницу, а не необработанный ответ backend. При этом request ID помогает найти событие в логах.
Express.js: централизованный error middleware
app.use((err, req, res, next) => {
const traceId = req.headers['x-request-id'] || crypto.randomUUID();
logger.error({
traceId,
message: err.message,
stack: err.stack,
route: req.originalUrl,
method: req.method
});
res.status(500).json({
type: 'https://example.ru/problems/internal-error',
title: 'Ошибка обработки запроса',
status: 500,
detail: 'Не удалось выполнить запрос. Повторите позже или обратитесь в поддержку.',
traceId
});
});
Важно: перед записью в лог нужен фильтр секретов. Нельзя автоматически писать req.body, если там есть паспорт, телефон, пароль, токен или медицинские данные.
Django
# settings.py
DEBUG = False
ALLOWED_HOSTS = ["example.ru"]
# logging filter должен маскировать sensitive fields:
SENSITIVE_FIELDS = ["password", "token", "authorization", "passport", "phone"]
Для Django критично, чтобы DEBUG = False был гарантированно включён в production. Ошибка с включённым debug-режимом может раскрыть настройки, переменные окружения, пути и внутренние данные.
Spring Boot
server.error.include-stacktrace=never
server.error.include-message=never
server.error.include-binding-errors=never
В Spring-приложениях удобно использовать @ControllerAdvice и возвращать безопасный ProblemDetail-ответ по RFC 9457. Технические детали отправляются в лог, публичный ответ остаётся коротким.
ASP.NET Core
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/error");
app.UseHsts();
}
Developer Exception Page нельзя включать в production. Ошибка должна вести на безопасный endpoint, который возвращает общий ответ и correlation ID.
Сообщения об ошибках и персональные данные в российском контексте
Для российских компаний важно учитывать 152-ФЗ и подзаконные требования к защите ПДн. Статья 19 152-ФЗ обязывает оператора принимать правовые, организационные и технические меры для защиты персональных данных от неправомерного или случайного доступа, уничтожения, изменения, блокирования, копирования, предоставления, распространения и иных неправомерных действий. Постановление Правительства №1119 устанавливает уровни защищённости ИСПДн, а приказ ФСТЭК №21 описывает группы мер, включая регистрацию событий безопасности, управление доступом, выявление инцидентов и реагирование.
Если сообщение об ошибке раскрывает персональные данные неавторизованному лицу, это нужно оценивать как возможный инцидент. Роскомнадзор на портале персональных данных указывает, что при установлении факта неправомерной или случайной передачи, предоставления, распространения или доступа к персональным данным, повлёкшего нарушение прав субъектов, оператор обязан уведомить уполномоченный орган в течение 24 часов, а в течение 72 часов предоставить результаты внутреннего расследования.
Важно не путать два состояния:
- Потенциальная уязвимость — приложение могло бы раскрыть данные, но факта доступа нет.
- Инцидент — данные действительно были раскрыты, переданы, предоставлены или доступны не тому лицу.
Во втором случае нужна процедура реагирования: фиксация факта, анализ логов, определение объёма данных, устранение причины, оценка вреда, внутренний отчёт и, если есть предусмотренные законом признаки, уведомление Роскомнадзора.
Типичные ошибки команд разработки и эксплуатации
Ошибка 1. Debug включён в production
Это классика. Приложение возвращает пользователю stack trace, переменные окружения, пути, конфигурацию. Часто встречается после аварийного релиза или ручной настройки.
Как избежать: запретить debug в production через CI/CD policy, runtime health check и контроль конфигурации.
Ошибка 2. Логируется весь request/response
На этапе отладки удобно писать в лог всё тело запроса. Но в реальном приложении там могут быть пароли, паспортные данные, телефоны, токены и персональные документы.
Как избежать: использовать allowlist полей для логирования, а не blacklist. Логировать только то, что действительно нужно.
Ошибка 3. Разные ошибки для существующих и несуществующих аккаунтов
Форма входа, регистрации и восстановления пароля часто раскрывает, есть ли такой пользователь. Это помогает атакующим собирать базу реальных аккаунтов.
Как избежать: одинаковые ответы для чувствительных сценариев авторизации и восстановления доступа.
Ошибка 4. Проброс внутренних ошибок зависимых сервисов
Например, платежный сервис вернул подробную ошибку, а приложение показало её пользователю без фильтрации.
Как избежать: нормализовать ошибки на уровне интеграционного слоя. Внешний raw response не должен уходить пользователю.
Ошибка 5. Корреляционный ID содержит смысловые данные
Иногда вместо случайного ID используют user ID, email, номер заказа или телефон. Это плохо: сам код ошибки превращается в источник раскрытия.
Как избежать: использовать UUID/ULID или другой случайный идентификатор без персональных данных.
Ошибка 6. Тестовые endpoints и debug-панели доступны из интернета
/debug, /actuator, /swagger, /phpinfo, /admin/test часто раскрывают больше, чем обычные ошибки.
Как избежать: закрывать такие endpoints сетевыми правилами, IAM, VPN, allowlist, а в production отключать всё лишнее.
Лучшие практики
- Единый стандарт ошибок. Опишите допустимые форматы для веб-интерфейса и API. Для API используйте RFC 9457.
- Единый error handler. Не обрабатывайте исключения вручную в десятках мест.
- Разделение публичного и внутреннего сообщения. Пользователю — безопасный текст, инженеру — защищённый лог.
- Correlation ID в каждом ответе. Это ускоряет поддержку и расследование.
- Маскирование данных. Поля
password,token,cookie,authorization,passport,phone,email,card,snils,innдолжны фильтроваться. - Контроль debug-режима. Production не должен возвращать developer exceptions.
- Защита логов. Логи — это актив с высоким риском. Нужны контроль доступа, ретеншн, шифрование, мониторинг и аудит.
- Тестирование ошибок. DAST и ручные проверки должны включать fuzzing, некорректные запросы, нарушение форматов, невалидные ID.
- Обучение разработчиков. Нужно объяснять не только «что нельзя», но и почему.
- Процесс реагирования. Если ошибка раскрыла ПДн, команда должна знать маршрут действий.
Сравнение подходов к обработке ошибок
| Подход | Преимущества | Недостатки | Когда использовать |
|---|---|---|---|
| Подробные ошибки пользователю | Удобно при разработке | Риск утечки ПДн и внутренней архитектуры | Только локальная разработка |
| Общие сообщения без ID | Безопаснее подробных ошибок | Сложно поддерживать пользователя | Небольшие сайты без сложной поддержки |
| Общие сообщения + correlation ID | Баланс UX и ИБ | Требует централизованных логов | Оптимальный вариант для бизнеса |
| RFC 9457 для API | Единый формат, удобно интеграциям |
Требует дисциплины в detail
|
REST API, микросервисы |
| API gateway normalization | Единая политика на периметре | Не заменяет исправления в коде | Микросервисы и большие API |
| Полное подавление деталей везде | Снижает риск раскрытия | Может ухудшить диагностику | Высокорисковые публичные сервисы, но только с хорошими логами |
Таблица преимуществ и недостатков безопасного error handling
| Плюсы | Минусы / ограничения |
|---|---|
| Снижает риск компрометации персональных данных | Требует изменений в коде и конфигурации |
| Усложняет разведку для атакующего | Нужна дисциплина логирования |
| Улучшает поддержку через correlation ID | Нужно обучать разработчиков и поддержку |
| Помогает расследовать инциденты | Не заменяет WAF, SAST, DAST и контроль доступа |
| Упрощает аудит и соответствие требованиям | Требует регулярной проверки при релизах |
| Повышает качество API | Нужна единая договорённость между командами |
Рекомендации эксперта
Если внедрять безопасную обработку ошибок с нуля, не начинайте с идеального документа на 40 страниц. Начните с практического мини-стандарта:
- список запрещённых данных в ошибках и логах;
- единый формат публичной ошибки;
- правила для авторизации и восстановления пароля;
- обязательный correlation ID;
- запрет debug в production;
- маскирование чувствительных полей;
- DAST-проверка публичных ошибок перед релизом;
- маршрут реагирования при обнаружении ошибки с ПДн.
Этого уже достаточно, чтобы закрыть большинство типовых проблем. Потом можно расширять: внедрять RFC 9457, автоматическое redaction, интеграцию с SIEM, правила обнаружения stack trace, pipeline-проверки и безопасные шаблоны для разработчиков.
Чек-лист внедрения
Для владельца продукта
- Все пользовательские ошибки понятны и не раскрывают технических деталей.
- Формы входа и восстановления пароля не позволяют определить существование аккаунта.
- Есть безопасный текст для 400/401/403/404/422/429/500/503.
- Есть инструкция для поддержки: как искать ошибку по correlation ID.
Для разработчика
- В production отключён debug.
- Есть global exception handler.
- Stack trace не возвращается пользователю.
- RFC 9457 или единый error contract используется для API.
- Ошибки зависимых сервисов не пробрасываются наружу без фильтрации.
- Request body не логируется целиком.
- Sensitive fields маскируются.
Для DevOps / SRE
- Настроены стандартные error pages на reverse proxy.
- В каждом запросе есть request ID / trace ID.
- Логи защищены RBAC и ретеншн-политикой.
- Debug endpoints закрыты.
- DAST проверяет ошибки перед релизом.
- SIEM получает события 5xx/4xx-аномалий.
Для ИБ / SOC
- Есть правила обнаружения stack trace и SQL errors в публичных ответах.
- Есть процесс triage ошибок с ПДн.
- Есть порядок уведомления ответственных при риске компрометации персональных данных.
- Проводятся регулярные проверки веб-приложений.
- Ведётся реестр исправлений по ошибкам безопасной обработки.
Практические сценарии: как ошибка превращается в инцидент
Сценарий 1. Личный кабинет показывает данные другого клиента в validation error
Компания обновляет форму заказа. При ошибке валидации backend возвращает весь объект customer, чтобы фронтенд мог подсветить поля. В тестовой среде это удобно. В production при некорректном ID заказа API начинает возвращать имя, телефон и email другого клиента в тексте ошибки. Ошибка заметна только при определённой комбинации параметров, поэтому долго остаётся незамеченной.
Что происходит на практике: пользователь делает скриншот, отправляет его в поддержку, а поддержка фиксирует, что в ответе API были данные третьего лица. Это уже не просто технический дефект. Нужно понять, были ли такие ответы у других пользователей, сколько записей раскрыто, за какой период, какие логи это подтверждают и нужно ли запускать процедуру уведомления.
Как избежать: не возвращать внутренние модели данных в ответе ошибки, использовать DTO для публичных ошибок, покрыть validation errors автотестами, добавить DAST-сценарии с некорректными ID и контроль отсутствия ПДн в response body.
Сценарий 2. Ошибка восстановления пароля раскрывает базу активных email
Форма восстановления пароля отвечает: «Пользователь найден, письмо отправлено» или «Email отсутствует в базе». Атакующий подаёт список адресов из утечек и получает точный список клиентов компании. Даже если пароли не украдены, база реальных аккаунтов — ценный актив для фишинга и credential stuffing.
Как избежать: всегда возвращать одинаковый текст: «Если аккаунт существует, инструкция будет отправлена». При этом внутри нужно логировать попытки массового перебора, ограничивать частоту запросов, включать антибот-механизмы и отправлять событие в SIEM.
Сценарий 3. Ошибка SQL помогает провести более точную атаку
Пользователь вводит нестандартный символ в поле поиска. Приложение возвращает ошибку с именем таблицы, названием поля и фрагментом SQL. Для атакующего это сокращает время разведки: он уже знает, как называется таблица, какие поля есть и какой тип БД используется. Дальше проверяются SQL injection, IDOR, слабые фильтры и ошибки авторизации.
Как избежать: параметризованные запросы, безопасная обработка исключений, отключение подробных SQL-ошибок в публичном ответе, WAF как дополнительный слой, тестирование негативных запросов в CI/CD.
Сценарий 4. Debug-страница раскрывает секреты интеграции
После аварийного релиза в production остаётся включённым debug. При ошибке приложение показывает переменные окружения, среди них S3_BUCKET, DATABASE_URL, JWT_SECRET, адреса внутренних сервисов. Такая ошибка может привести не только к компрометации персональных данных, но и к компрометации инфраструктуры.
Как избежать: запрет debug в production на уровне pipeline, проверки переменных окружения при старте приложения, отдельный шаблон конфигурации для production, секрет-сканирование репозитория и логов, автоматический alert при появлении слов stacktrace, Traceback, SQLException, APP_DEBUG=true в публичных ответах.
Как тестировать безопасные сообщения об ошибках
Проверять ошибки нужно не только после инцидента. Это часть нормального цикла разработки.
Минимальный набор тестов
- Открыть несуществующий URL и проверить 404.
- Отправить некорректный JSON в API.
- Передать слишком длинное значение в поле формы.
- Попробовать загрузить файл неправильного типа.
- Обратиться к ресурсу без авторизации.
- Обратиться к чужому объекту по ID.
- Сломать интеграцию с тестовым внешним сервисом.
- Проверить ошибку восстановления пароля для существующего и несуществующего email.
- Проверить, не содержит ли ответ stack trace, SQL, IP, hostnames, tokens, ПДн.
- Проверить, создаётся ли внутренний лог с correlation ID.
Что искать в ответах
Для автоматизированной проверки удобно использовать список маркеров:
Exception,Traceback,Stack trace,NullPointerException,SQLException;SELECT,INSERT,UPDATE,DELETE,FROM users;/var/www,/home/,C:\,appsettings,.env;Authorization,Bearer,Set-Cookie,sessionid;password,secret,token,apikey,client_secret;- внутренние домены:
.local,.svc.cluster.local,localhost,10.; - персональные шаблоны: email, телефон, паспорт, СНИЛС, ИНН.
Зрелые команды добавляют такие проверки в DAST, API-тесты и pre-release checklist. Если в ответе обнаружен запрещённый паттерн, релиз блокируется до исправления.
Политика безопасных сообщений об ошибках: пример структуры
Политика не должна быть длинной. Её задача — дать разработчикам, DevOps и поддержке одинаковое понимание.
1. Назначение
Документ описывает правила формирования сообщений об ошибках для веб-приложений, API, мобильных приложений и внутренних сервисов, чтобы снизить риск раскрытия внутренних деталей и компрометации персональных данных.
2. Запрещённая информация
В публичных ошибках запрещено показывать: ПДн, пароли, токены, cookie, session ID, stack trace, SQL-запросы, внутренние IP и домены, пути к файлам, версии компонентов, значения переменных окружения, настройки инфраструктуры.
3. Разрешённая информация
Разрешено показывать: общий тип ошибки, безопасное описание, действие для пользователя, HTTP-статус, correlation ID, ссылку на поддержку.
4. Требования к логам
Подробности ошибок пишутся только в защищённые журналы. Логи должны проходить маскирование, храниться по политике ретенции, иметь контроль доступа и передаваться в SIEM при необходимости.
5. Требования к API
Для REST API рекомендуется единый формат ошибок, например RFC 9457. В поле detail нельзя включать чувствительные значения. Validation errors должны показывать названия полей, но не раскрывать лишние данные.
6. Контроль и ответственность
За внедрение отвечает команда разработки, за контроль конфигурации — DevOps/SRE, за проверку и мониторинг — ИБ/SOC, за коммуникацию с пользователями — поддержка. Нарушения фиксируются как дефекты безопасности.
Отчётность для ИБ и руководства
Безопасная обработка ошибок должна быть измеримой. Иначе она быстро превращается в декларацию.
Полезные метрики:
- количество 5xx-ошибок по сервисам;
- количество ошибок с запрещёнными паттернами в ответах;
- доля ошибок с correlation ID;
- количество попыток user enumeration;
- количество публичных endpoints с debug-признаками;
- среднее время исправления ошибок с раскрытием данных;
- количество инцидентов, где причина связана с error handling;
- процент сервисов, подключённых к единому error handler;
- процент сервисов, прошедших DAST-проверку ошибок.
Для руководства это можно переводить в простой язык: сколько рисков раскрытия данных найдено, сколько устранено, какие сервисы остаются проблемными, сколько времени занимает исправление. Для ИБ-аналитиков важнее технические детали: endpoint, компонент, тип раскрытия, пример безопасной замены, владелец сервиса.
Как поступают зрелые компании
Зрелые компании не ждут, пока пользователь пришлёт скриншот с чужими данными. Они строят процесс заранее.
- Стандарт ошибок принимается как часть API governance. Все команды используют единый формат.
- Внутренние библиотеки уже содержат безопасный error handler. Разработчик не пишет обработку ошибок с нуля.
- Debug запрещён технически. Нельзя случайно выкатить
DEBUG=true, потому что pipeline остановит сборку. - Логи фильтруются автоматически. Маскирование работает на уровне logging framework и log pipeline.
- DAST проверяет не только XSS и SQLi, но и утечки в ошибках. Негативные сценарии входят в релизный контроль.
- SOC видит аномалии. Серия ошибок 404/403/500, похожая на разведку, становится событием мониторинга.
- Поддержка работает по correlation ID. Пользователь не получает подробности, но проблема быстро находится.
- Есть регламент для ошибок с ПДн. Если в ответе была компрометация персональных данных, команда знает, кого уведомлять и какие сроки учитывать.
FAQ
Можно ли вообще показывать пользователю причину ошибки?
Да, но только на уровне действия. Например: «Проверьте формат файла» — нормально. «Файл /var/www/uploads/passports/ivanov.pdf не найден» — небезопасно.
Нужно ли скрывать все 404?
Нет. 404 сам по себе нормальный HTTP-статус. Но не стоит раскрывать, какие внутренние ресурсы существуют, а какие нет, если это чувствительная зона. Для API авторизации лучше избегать различий, которые помогают enumeration.
Можно ли писать stack trace в логи?
Можно, если логи защищены, доступ ограничен, данные проходят фильтрацию, а в stack trace не попадают секреты и ПДн. Но писать stack trace пользователю нельзя.
Correlation ID безопасен?
Да, если он случайный и не содержит user ID, email, номер заказа, телефон или другую смысловую информацию. Лучше использовать UUID/ULID.
Нужно ли уведомлять Роскомнадзор, если ошибка могла раскрыть ПДн?
Нужно сначала провести оценку фактов. Если установлен факт неправомерной или случайной передачи, предоставления, распространения или доступа к ПДн, повлёкший нарушение прав субъектов, оператор обязан действовать по процедуре 152-ФЗ, включая уведомление Роскомнадзора в установленные сроки.
Нужно ли использовать RFC 9457?
Это хорошая практика для HTTP API. Он не решает безопасность сам по себе, но помогает стандартизировать ошибки. Главное — не наполнять detail чувствительной информацией.
Чем отличаются ошибки для пользователя и для поддержки?
Пользователь видит безопасный текст и код обращения. Поддержка по этому коду находит внутренний лог, где есть техническая диагностика. Это позволяет помогать пользователю без раскрытия внутренних деталей.
Как проверить, что приложение не раскрывает лишнее?
Используйте DAST, ручное тестирование негативных сценариев, проверку debug-конфигураций, SAST-правила, секрет-сканирование логов и регулярные ревью error handling.
Основные выводы
Безопасные сообщения об ошибках — это важная часть защиты веб-приложений и API. Они снижают риск компрометации персональных данных, скрывают внутреннюю архитектуру от атакующих, помогают соблюдать требования законодательства и упрощают расследование инцидентов.
Зрелый подход строится на простых принципах: пользователь получает понятное безопасное сообщение, инженер — защищённую диагностику, SOC — события для корреляции, а бизнес — снижение риска утечек и штрафов. Если сейчас приложение показывает stack trace, SQL-запросы, внутренние пути или персональные данные в ошибках, это не косметический дефект. Это уязвимость, которую нужно исправлять как часть Secure SDLC.
Источники
- OWASP Error Handling Cheat Sheet — https://cheatsheetseries.owasp.org/cheatsheets/Error_Handling_Cheat_Sheet.html
- OWASP Logging Cheat Sheet — https://cheatsheetseries.owasp.org/cheatsheets/Logging_Cheat_Sheet.html
- OWASP Top 10 A05:2021 Security Misconfiguration — https://owasp.org/Top10/2021/A05_2021-Security_Misconfiguration/
- OWASP ASVS V16 Security Logging and Error Handling — https://github.com/OWASP/ASVS
- MITRE CWE-209 — https://cwe.mitre.org/data/definitions/209.html
- MITRE CWE-210 — https://cwe.mitre.org/data/definitions/210.html
- MITRE CWE-215 — https://cwe.mitre.org/data/definitions/215.html
- MITRE CWE-532 — https://cwe.mitre.org/data/definitions/532.html
- NIST SP 800-53 Rev. 5, SI-11 Error Handling — https://csrc.nist.gov/pubs/sp/800/53/r5/upd1/final
- RFC 9457 Problem Details for HTTP APIs — https://www.rfc-editor.org/rfc/rfc9457.html
- Портал персональных данных Роскомнадзора: уведомление об инциденте — https://pd.rkn.gov.ru/incidents/
- 152-ФЗ, статья 19 — https://legalacts.ru/doc/152_FZ-o-personalnyh-dannyh/glava-4/statja-19/
- Постановление Правительства РФ №1119 — https://legalacts.ru/doc/postanovlenie-pravitelstva-rf-ot-01112012-n-1119/
- Приказ ФСТЭК России №21 — https://legalacts.ru/doc/prikaz-fstek-rossii-ot-18022013-n-21/
