ESPN DeportesCómo las Valkyries fueron de la expansión hasta las Finales WNBAESPNFIFA president Infantino received undisclosed $1.7M World Cup paymentThe Jerusalem PostHerzog honors Israel Bonds for raising billions post-Oct 7 while mourning northern school tragedyInquirer300 kilos of trash collected in Sarangani Bay mangrove cleanupBollywood HungamaSadhu Tiwari to perform Nayyi Navelli song ‘Awadhiya Ke Raja’ at Ram Ki Paidi in AyodhyaRTP DesportoLens - Sporting CPDaily MaverickHow the Middle East conflict is reshaping the multipolar global orderRadio Times'It was jaw dropping!'The Hollywood Reporter‘Queen Silvia’ Ditches the Glass Slipper for Un-Cinderella Royal Romance3DNewsМарсоход NASA Perseverance побил рекорд пробега на другой планете — и останавливаться не собираетсяZDF heuteEntdecken Sie das ZDF-NachrichtenstudioBBC NewsMurder investigation after four people die in arson attack
The Daily Newsstand · Free, Always
Tuesday, October 13, 2026

Session replay и 152-ФЗ: что нельзя записывать и как мы маскируем поля

Translate

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

Привет! Я Паша, работаю над российским сервисом записи сессий пользователей. В этой статье я расскажу, как мы добиваемся соответствия продукта российским законам с точки зрения персональных данных, что в нашей нише не так уж просто. И я не юрист: юридическая часть ниже описывает, как мы это поняли. Проверяйте со своим юристом.

Первый вопрос, который задают про запись сессий: «а вы видите, что я ввожу в поле?». Честный ответ: технически скрипт записи видит всё, что видит браузер. Вопрос только в том, что он отправит на сервер.

Ниже о том, где обычно утекает лишнее, как с этим работать и при чём здесь 152-ФЗ.

Что видит скрипт записи

Мы используем библиотеку rrweb для записи экрана, которая сериализует DOM целиком: текст на странице, значения полей, атрибуты элементов. Отсюда несколько мест утечки, и очевидное среди них только одно.

  • Поля ввода. Это знают все.

  • Текст, который уже отрисован на странице. Имя в шапке личного кабинета, баланс счёта, номер договора, последние цифры карты. Пользователь ничего не вводил, а данные в записи есть. Если маскировать только поля ввода, этот текст останется в записи.

  • Textarea и contenteditable. Переписка с поддержкой, комментарии, заметки.

  • Автозаполнение браузера. Значение появляется в поле без единого нажатия клавиши. Обработчик ввода может его не заметить, а снимок DOM заметит.

  • URL. Email или токен в query string попадают в запись вместе с адресом страницы.

Маскировать на клиенте, а не на сервере

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

В rrweb для этого есть штатные опции:

maskAllInputs заменяет значения полей на звёздочки. maskTextSelector маскирует текст в выбранных элементах. blockClass вырезает элемент целиком, оставляя в записи пустой прямоугольник того же размера, чтобы не поехала вёрстка.

Отдельно про текст, который уже отрисован на странице. Маскировать только поля ввода здесь недостаточно: имя, баланс или ответ оператора в чате лежат в обычных блоках. Поэтому принудительное маскирование у нас работает с любым элементом: весь текст внутри него и его потомков заменяется звёздочками ещё в браузере. По смыслу это тот же приём, что maskTextSelector, только правило можно задать и в разметке, и селектором в настройках.

А если данные можно вообще не выводить целиком, это всё равно лучший вариант: последние четыре цифры карты вместо полного номера, частично скрытый номер договора. Такой подход защищает не только от записи сессий, но и от скриншотов, расширений браузера и чужих глаз за спиной.

Что маскируется всегда

Пароли и платёжные поля мы решили маскировать без возможности отключить.

Наш трекер считает поле паролем или платёжным, если выполняется хотя бы одно из условий:

  • Тип поля password.

  • Атрибут autocomplete со значением cc-*: cc-number, cc-csc, cc-exp, cc-exp-month, cc-exp-year, cc-name и другие. Составные значения тоже распознаются, например autocomplete="billing cc-number".

  • Имя или идентификатор поля (name, id, data-name) похожи на платёжные: card_number, cardNumber, cc-num, cvv, cvc, csc, exp_month, expiry_date, cardholder, pan и похожие. Регистр, дефисы, точки и подчёркивания не важны.

  • Подсказка в поле (placeholder, aria-label, title) говорит о карте: «Номер карты», «Срок действия», «ММ/ГГ», «Держатель карты», «Имя на карте», «Код безопасности», «CVV», “CVC”, “Card number”, “Expiry date”, “Security code”.

Решение «без возможности отключить» далось не сразу: на этапе отладки формы оплаты очень хочется видеть, что ввёл пользователь. Но отключаемая защита рано или поздно оказывается отключённой на проде, потому что кто‑то отлаживал форму и забыл вернуть настройку.

Blacklist или whitelist

Дальше выбор режима. Их два, и в каждом нужен обратный рычаг.

Blacklist: записываем всё, кроме помеченного. Запись полезная, видно, что человек вводил и на каком шаге ошибся. Слабое место у этого режима одно: новое поле. Разработчик добавил в форму «Серия и номер паспорта», не повесил класс маскирования, и паспортные данные поехали в записи. Никто этого не заметит, потому что всё работает. Страхует только автоопределение паролей и платёжных полей, которое работает в любом режиме, но паспорт оно не угадает.

Whitelist: маскируем всё, кроме явно разрешённого. Безопасно по умолчанию, но запись превращается в строки звёздочек, и понять, почему пользователь застрял на форме, становится заметно сложнее.

Мы сделали whitelist режимом по умолчанию для всех проектов, не только для финтеха. Аргумент простой: ошибка в whitelist оборачивается звёздочками вместо полезных данных, ошибка в blacklist оборачивается утечкой персональных данных. Первое неудобно, второе необратимо. Поля, которые действительно нужно видеть, открываются точечно. Работать в blacklist можно, но это осознанный выбор, и тогда каждую новую форму стоит проверять на ревью.

Исключения нужны в обе стороны: в whitelist открыть отдельные поля, в blacklist принудительно закрыть любой элемент, не только поле. Мы дали два способа задать такое правило: классом в разметке или CSS‑селектором и data‑атрибутом в настройках проекта. Второй способ нужен на случай, когда утечку нашли уже в проде: закрыть элемент можно селектором, не дожидаясь релиза.

При чём здесь 152-ФЗ

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

Запись сессии, привязанная к email, это обработка персональных данных. Без оговорок. Есть ирония в том, что самая полезная для команды вещь, привязка записи к конкретному пользователю, делает данные чувствительнее. Анонимная запись и запись с email клиента с точки зрения закона различаются сильно.

Персональные данные граждан РФ при сборе должны записываться и храниться в базах на территории России. Если сервис записи держит данные за рубежом, появляется отдельный вопрос трансграничной передачи со своими требованиями.

С 1 сентября 2025 года согласие на обработку персональных данных оформляется отдельным документом. Пункт внутри оферты или политики конфиденциальности больше не подходит.

И важное: маскирование не заменяет согласие. Даже если в записи нет паролей и карт, в ней остаются email, поведение на сайте и технические данные устройства.

View the original on Хабр →

KioskNews shows a cleaned-up reading view extracted from the publisher’s page — the original always lives on their site, not ours.