EN Прислать проект
Все статьи

Логи без персональных данных

Что писать в лог, что маскировать, сколько хранить и как идентификатор запроса помогает разбираться в проблемах, не зная, кто был пользователь.

· 4 минБезопасностьКод

Логи обычно растут сами. Кто-то добавил console.log(req.body), чтобы поймать баг, баг починили, строчка осталась. Через полгода в логах лежат пароли из формы входа, телефоны из анкет и токены из заголовков, а доступ к логам есть у всех разработчиков, у сервиса мониторинга и у подрядчика, которому дали посмотреть одну ошибку.

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

Что писать

Хорошая строка лога отвечает на вопросы «что произошло, где и чем кончилось», а не «кто этот человек»:

  • идентификатор запроса;
  • маршрут в виде шаблона: /orders/:id, а не /orders/8412?token=...;
  • метод, код ответа и время выполнения;
  • внутренний идентификатор пользователя — непрозрачный, из базы, а не почта;
  • для ошибок — тип, сообщение и стек;
  • ключевые события продукта: заказ создан, оплата прошла, подписка отменена.

Этого хватает, чтобы разобраться почти в любой проблеме. Если нужно понять, кто этот пользователь, это делается в основной базе, где есть права доступа и журнал.

Что не писать никогда

  • пароли, коды подтверждения и одноразовые ссылки;
  • токены, ключи API, заголовки Authorization и Cookie;
  • номера карт и платёжные реквизиты;
  • тела запросов и ответов целиком;
  • содержимое обращений к ИИ, если туда попадает текст пользователя.

Почты и телефоны, если без них никак, маскируй: a***@example.com, последние две цифры номера. IP-адрес тоже персональные данные во многих юрисдикциях; если он нужен для борьбы со злоупотреблениями, храни его коротко или в обрезанном виде.

Разрешённые поля, а не запрещённые

Список того, что нельзя логировать, всегда отстаёт: завтра появится поле passport_number, и о нём никто не вспомнит. Надёжнее обратный подход — логировать объекты только через явный набор разрешённых полей. Маскирование на уровне логгера остаётся страховкой для того, что всё-таки проскочило:

const logger = pino({
  redact: {
    paths: ["req.headers.authorization", "req.headers.cookie", "*.password", "*.token"],
    censor: "[redacted]",
  },
});

Отдельно проверь трекер ошибок. Многие из них по умолчанию собирают тела запросов, куки и локальные переменные — у них есть настройки очистки, и их стоит включить в первый же день.

Секреты в адресах

Ссылка для сброса пароля с токеном в параметре запроса попадает в логи прокси, балансировщика и CDN, причём в те, которые ты не контролируешь. Если токен в адресе неизбежен, он должен быть одноразовым и короткоживущим, а логирование адресов — без параметров запроса.

Идентификатор запроса

Каждый входящий запрос получает уникальный идентификатор на самом первом шаге: на прокси или в первом обработчике. Дальше он передаётся во все внутренние вызовы, попадает в фоновые задачи, которые запрос поставил, и пишется в каждую строку лога.

Это даёт две вещи. Во-первых, по одному идентификатору видна вся история запроса через все сервисы. Во-вторых, его можно вернуть в заголовке ответа и показать на странице ошибки. Человек пишет в поддержку «у меня ошибка, код такой-то», и ты находишь её за секунды, не спрашивая его почту и не ища по времени.

Сколько хранить

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

Короткий срок хранения решает ещё одну задачу: когда пользователь просит удалить его данные, логи очищаются сами, без отдельной операции.

Кто читает

Доступ к логам — такой же доступ к данным, как к базе. Его стоит выдавать по необходимости и пересматривать, а внешним подрядчикам давать конкретную выборку, а не весь поток.

SUBXCAT может пройтись по тому, что сейчас пишется в логи твоего проекта, и настроить маскирование и идентификаторы запросов.

Хочешь, сделаем это за тебя?

Расскажи о проекте ассистенту — через пять минут будет примерная смета, через 48 часов разбор.

Созвон с командой 20 минут: инженер, дизайнер и маркетолог посмотрят на проект вместе с тобой.
Записаться на звонок