Краткое введение

Недавно я имел удовольствие интегрировать LogRocket в большое приложение и, наконец, отказался от устаревшего инструмента мониторинга под названием Tealeaf, который использовался компанией в течение многих лет. Потратив несколько недель на изучение различных функций и изучение того, как реализован LogRocket, я понял, что это феноменальная программа!

LogRocket предоставляет вам Javascript SDK для загрузки и инициализации в вашем веб-приложении, которое затем фиксирует действия пользователя, сетевые запросы / ответы, операторы консоли и ошибки Javascript. Затем все они объединяются в пользовательский сеанс, который позже можно воспроизвести, как если бы вы отлаживали их сеанс с помощью инструментов разработчика Chrome. Это позволяет вам находить и отлаживать ошибки, о которых пользователь, скорее всего, никогда не сообщил бы, и, что наиболее важно, визуально видеть, что делал пользователь, когда произошла ошибка!

LogRocket достигает всего этого с незначительным влиянием на производительность вашего приложения, используя некоторые продвинутые API-интерфейсы Javascript, такие как: MutationObserver для отслеживания изменений в пользовательском интерфейсе вашего приложения, небольшие прокладки для захвата XMLHTTPRequest иfetch запросов на хранение сетевых журналов и Web Workers чтобы выгрузить тяжелые вычисления в отдельный поток.

Внутри этих рабочих потоков веб-приложений вся логика, используемая для сжатия огромного количества событий, собирается, группируется и затем отправляется в API LogRocket. У меня была возможность пройти через это, пока я пытался понять, как написать интеграционный тест для нашего приложения, и как достигается сжатие, это действительно круто (подсказка: Побитовые операторы и Типизированные массивы). Возможно, об этом позже.

Очистка данных

Хотя я мог часами говорить о том, насколько хорош LogRocket, цель этой статьи - описать мою конкретную задачу при настройке моего приложения для использования LogRocket, которая сосредоточена вокруг настройки того, какие сетевые данные LogRocket отправляет в их API. Как упоминалось выше, LogRocket захватывает весь сетевой трафик и записывает полезные данные и заголовки запросов и ответов, которые будут просмотрены позже в пользовательских сеансах. Однако по умолчанию все данные отправляются в LogRocket и затем могут быть просмотрены любым, у кого есть доступ к вашему инструменту администрирования LogRocket. Поскольку мое приложение собирает все виды конфиденциальных данных о клиентах (например, SSN, дату рождения, имя, фамилию и т. Д.), Необходимо было что-то сделать, чтобы данные о клиентах не отправлялись в API LogRocket, а затем просматривались в виде обычного текста. .

К счастью, LogRocket SDK, используемый для инициализации вашего экземпляра LogRocket, предоставляет параметры для настройки - один из них является перехватчиком, который можно использовать для захвата запросов и ответов перед отправкой в ​​LogRocket (см. Сетевые документы SDK) с именами requestSanitizer и responseSanitizer. Эти два крючка позволяют вам редактировать все, что связано с запросами и ответами, то есть полезную нагрузку, заголовки, URL-адрес и т. Д., Или полностью их игнорировать.

В документации LogRocket приведены примеры того, как полностью игнорировать запросы или удалять тело запроса в зависимости от определенных условий. Однако для своего приложения я хотел найти способ разрешить прохождение каждого запроса, но при этом части запроса / ответа, содержащие конфиденциальные данные, должны быть замаскированы.

Дезинфицирующее решение

Решение, к которому я в конечном итоге пришел, оказалось очень полезным для предотвращения попадания потенциально конфиденциальных данных в LogRocket в большом устаревшем приложении и позволило записывать каждый запрос / ответ.

Окончательное решение заключалось в наличии списка строк, который служил бы массивом для проверки того, соответствует ли имя ключа в полезной нагрузке строке в этом списке (по сути, нечеткий поиск), и если да, то это имя ключа будет считаться « чувствительна »и замаскирована перед возвратом в LogRocket. Логика поиска выполнялась в каждом requestSanitizer и responseSanitizer хуке. Все это в принципе можно свести к следующему псевдокоду:

import LogRocket from 'logrocket';
// if a payload key matches any string in this list, it is private
const privateFieldNames = [
  'ssn',
  'firstName',
  'birthDate'
];

LogRocket.init('app/id', {
  network: {
    requestSanitizer(request) {
       // search the request.body
       // mask the value of any key name that matches a
       // string in the list above
       // return the edited request
    }
  }
});

Первым шагом было собрать список имен ключей, которые могут отображаться в полезной нагрузке в нашем приложении. К счастью, в компании уже была некоторая документация по этому поводу, также были очевидны некоторые ключевые имена, содержащие определенные слова (например, «ssn», «BirthDate», «пароль»). Вторая и последняя часть заключалась в написании логики поиска в хуках дезинфицирующего средства запроса / ответа, которые необходимы для глубокого поиска объектов и массивов.

Заключение

После некоторого тестирования и полной реализации упомянутого выше решения я решил упаковать его в плагин для LogRocket:

Https://github.com/jbailey4/logrocket-fuzzy-search-sanitizer.

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

Некоторые другие вещи, которые следует рассмотреть как возможные альтернативы:

  • является ли ваш экземпляр LogRocket API активным или нет. Если он размещен на частном сервере, это может сыграть роль в том, что вы решите разрешить / запретить как конфиденциальные данные.
  • если вы управляете своими ответами API, вы можете создать некий стандарт для ответов, содержащих конфиденциальные данные, что-то вроде SSN_private - тогда интерфейс может просто отключить часть _private, чтобы определить, содержит ли ключ конфиденциальную информацию.