awesome-everything EN
↑ Обратно к восхождению

Наблюдаемость

PII-редакция и log injection

Суть Логи — самый простой telemetry-сигнал для утечки чувствительных данных и самый сложный для очистки. Редактируй в источнике, защищайся в глубину на collector''''е и никогда не интерполируй пользовательский ввод в log-messages.
Высота — путь к senior
НольJuniorMiddleSenior
Ты на senior-высоте — в орбите
◷ 12 min

Команда завершает SOC 2 аудит. Аудитор находит сырые email-адреса и auth-токены в трёх месяцах indexed-log-хранения. Логи никогда не числились как data store. Remediation занимает шесть недель и обходится дороже, чем изначальная logging-инфраструктура.

Почему логи — PII-риск

Логи генерируются в hot-path каждого запроса. Они накапливают request body’и, headers, database-запросы, stack trace’ы — любой из них может нести чувствительные данные, если инженер не был аккуратен.

Типичные PII-паттерны из реальных инцидентов: полные request body’и включая Authorization-заголовки и session-токены, email-адреса, залогированные как контекст userId, телефонные номера в user-submitted-полях форм, сырые SQL-запросы с пользовательским вводом, stack trace’ы с object-dump’ами, включающими записи клиентов.

Проблема накапливается: логи хранятся неделями или месяцами, реплицируются в cold storage и читаемы значительно более широкой аудиторией, чем primary-БД. Утечка log-backend’а открывает данные, которые никогда не должны были там находиться.

Источник PIIКак попадает в логиMitigation
Auth-токены / паролиПолное request body залогировано на DEBUG или при ошибкеDeny-list req.headers.authorization, body.password
Email-адресаЗалогированы как user-контекст или параметр поискаЛогировать только opaque user_id; deny-list user.email
Payment-данные (PAN, CVV)Сырой payment form body залогирован при validation errorDeny-list payment.card.*; логировать только last-4 и токен
Stack trace’ы с даннымиException-сериализатор дампает полный object graphОбрезать exception body на уровне logger’а; логировать только error type и message

Редакция в источнике

Logger SDK — правильная первая линия защиты. Каждый крупный продакшн-logger поддерживает deny-list, убирающий известные sensitive-пути до сериализации:

  • pino (Node.js): опция redact принимает массив dot-notation-путей (['req.headers.authorization', 'body.password', 'user.email']). Pino заменяет значения на [Redacted] перед записью. Overhead: примерно 2 мс на 1000 сообщений для 5 полей.
  • log4j2 (JVM): pattern-converter’ы и Rewrite-appender’ы могут убирать поля по имени ключа.
  • structlog (Python): processor в цепочке processor’ов может убирать или хешировать sensitive-ключи до рендеринга.
  • slog (Go): custom Handler оборачивает base handler и фильтрует атрибуты до записи.

Статическая редакция (известные пути полей) дёшева. Динамическая редакция (regex по всему message body) в 4-10 раз дороже и должна использоваться только для неструктурированных полей, где невозможно заранее перечислить пути.

Defence in depth: tier collector’а

Application-level редакция ловит намеренные пути. Tier collector’а ловит то, что приложение пропускает — сторонние библиотеки, логирующие request-объекты, ошибки, сериализующие неожиданный контекст, или новый сервис, ещё не принявший per-org wrapper-logger.

OTel Collector, Fluent Bit и Vector поддерживают redaction-processor’ы, прогоняющие regex-паттерны по атрибутам log-записи до отправки. Паттерн: убирать известные PII-форматы (email-адреса, шаблоны телефонных номеров, последовательности похожие на credit-card) в каждой строке независимо от имени поля. Это добавляет latency в collector-pipeline (20-50 мкс на строку для набора из 5 паттернов), но работает вне critical application-path и стоит своей цены.

Продакшн-правило: deny-list в источнике для известных полей; regex scrubber на collector’е как safety net. Никогда не полагайся на собственное маскирование log-backend’а как на первый или единственный слой — к тому времени данные уже покинули хост.

Почему это работает

Используй opaque internal identifier’ы в логах. Log-строка должна нести user_id: 42 (внутреннее целое число), никогда email: alice@example.com. Когда support-инженеру нужно отладить проблему Алисы, он ищет её внутренний id в primary-БД (операция с audit-следом), затем фильтрует логи по id. Это намеренный friction: audit-trail записывает, кто смотрел чьи данные. Right-to-erasure по GDPR также проще: когда аккаунт Алисы удалён из primary store, все её логи де-идентифицированы через разрыв маппинга — никакие логи не нужно переписывать.

Log injection: security failure-mode

Log injection (CWE-117) происходит, когда пользовательский ввод конкатенируется или интерполируется в log-message без санитизации. Две формы атаки:

Newline injection: ввод содержит литеральный newline. Log-строка вроде INFO: received comment: <user input> разделяется на две строки, когда ввод содержит newline с последующим сформированным payload — ERROR: admin user X deleted production database. Downstream-парсеры, SIEM-rules и audit-trail consumers трактуют обе строки как реальные записи. Манипуляция audit-trail — учебниковый сценарий.

JSON structural injection: в JSON-выводе, если пользовательский ввод конкатенируется в string-поле без escaping — а не передаётся как value JSON-сериализатору — special-characters могут закрыть текущую строку и инжектировать новые key-value-пары, портя log-запись и потенциально обходя SIEM-фильтры, полагающиеся на конкретные значения полей.

Уязвимость Log4Shell (CVE-2021-44228, декабрь 2021) была родственным, но отдельным fail: feature message lookup log4j2 обрабатывал log-message-контент как шаблон, позволяя JNDI-lookup’ам в user-controlled строках триггерить remote code execution. Урок обобщается: log-message-контент — input surface.

Предотвращение структурное: никогда не интерполируй пользовательский ввод в log-message-строки. Всегда передавай пользовательский ввод как типизированный атрибут-field, позволяя JSON-сериализатору обрабатывать escaping:

// Уязвимо — user input в message-строке
logger.info(`received comment: ${req.body.comment}`);

// Безопасно — user input как типизированное поле
logger.info({ event: "comment_received", comment: req.body.comment }, "comment received");

Сериализатор escape’ит значение поля, делая инъекцию структурно невозможной независимо от содержимого ввода.

Викторина

Команда логирует raw user-submitted строки в поле message. Пользователь отправляет текст с литеральным newline и сформированным JSON-объектом, выглядящим как реальная ERROR log-строка. Класс failure?

Викторина

В production-ready logging setup, где должна работать PII-редакция?

Расставь шаги по порядку

Упорядочь шаги по remediating PII-утечки, обнаруженной в продакшн-логах:

  1. 1 Идентифицировать источник: какой log-вызов или библиотека эмитит sensitive-поле
  2. 2 Немедленно добавить путь поля в logger SDK deny-list, чтобы остановить новую утечку
  3. 3 Добавить regex scrubber на tier'е collector'а как second-pass safety net
  4. 4 Оценить окно воздействия: сколько хранились логи, у кого был доступ
  5. 5 Подать data-incident report по GDPR / compliance требованиям, если личные данные были открыты
  6. 6 Добавить CI-проверку или поле PR-template для предотвращения повторного введения
Вспомните перед уходом
  1. 01
    Объясни log injection (CWE-117): две формы атаки и структурное предотвращение.
  2. 02
    Почему редакция только на log-backend'е недостаточна как единственный слой?
  3. 03
    Как правильно обрабатывать 'надо отладить проблему конкретного пользователя' без логирования PII?
Итог

Логи накапливают PII через request body’и, headers, SQL-запросы и stack trace’ы — часто без намерения инженеров. Требуются два слоя редакции: logger SDK deny-list убирает известные sensitive-пути до сериализации (дёшево, детерминированно), и collector-tier regex scrubber ловит то, что пропускает приложение (немного дороже, ловит случайные утечки и сторонние библиотеки). Никогда не интерполируй пользовательский ввод в log-message-строки — передавай его как типизированный атрибут и дай JSON-сериализатору обработать escaping, делая log injection структурно невозможным. Используй opaque internal ID (не email, телефон или имя), чтобы логи были безопасны по дизайну и GDPR erasure обрабатывался разрывом ID-маппинга, а не переписыванием log-архивов. Цена PII postmortem — compliance-уведомление, аудит, remediation — многократно превышает overhead source-level редакции.

Связанные уроки
встречается в268
Продолжить восхождение ↑Propagation trace-контекста в логах
хоткеи развернуть
поиск
K
пред. пьеса
k
след. пьеса
j
тиры
t
это меню
?
sources3
expand
  1. 01
  2. 02
  3. 03

Trademarks belong to their respective owners. Editorial reference only.