Политика логирования в приложениях: исключение персональных данных и автоматические проверки на этапе сборки

Политика логирования в приложениях: исключение персональных данных и автоматические проверки на этапе сборки

Изображение: recraft

В современном мире все чаще возникают утечки персональных данных. Причины могут быть разными: от взлома до простой человеческой неосторожности.

В 2025 году число атак на российские ИТ-системы превысило 63 тыс., это на 27% больше, чем в 2024. При этом две трети кибератак направлены на объекты критической информационной инфраструктуры. Последствия утечек персональных данных могут оказаться очень серьезными, а значит, нужно бороться с причинами их возникновения. Например, можно привлекать специалистов по информационной безопасности, использовать специальное ПО, разрабатывать определенные регламенты и процессы.

Основа этой большой задачи – выявление потенциальных источников персональных данных, которые можно задействовать в процессе утечки. Далеко не всегда такими источниками становятся большие БД или системы кадрового учета, иногда все происходит в совсем неприметном месте. Именно о таком источнике и методе противодействия утечке из него пойдет речь в этой статье.

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

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

Предотвратить подобные ситуации помогают инструменты статического анализа кода (Static Application Security Testing, SAST). Они умеют выявлять участки кода, где логируются «чувствительные» данные, нет маскирования персональной информации, используются небезопасные методы ее обработки. Ценность SAST-анализаторов в том, что они работают системно и регулярно, снижая зависимость от человеческого фактора.

Далее будет пример, в котором SAST-анализатор Semgrep Code проверит блока кода на предмет несоответствия требованиям и по результатам предоставит отчет. Возьмем блок кода, написанного на Python:

LOGGER.infoNew user registered: %s«, user_record) LOGGER.infoNew user registered: %s«, user_record)

Он выводит в лог приложения информацию, сосредоточенную в переменной user_record. Зададим ее значение в виде словаря данных:

{   

        "user_id": "123",                                                                                                                                                                                                 

        "full_name": "Ivan Petrov",                                                                                                                                                                                

        "email": "ivan.petrov@example.com",                                                                                                                                                                        

        "phone": "+7-999-123-45-67",                                                                                                                                                                               

        "passport": "4010 123456",                                                                                                                                                                                 

}

Тогда результатом выполнения блока кода с будет вот такое сообщение в логе приложения:

INFO:demo:New user registered: {'full_name': 'Ivan Petrov', 'email': 'ivan.petrov@example.com', 'phone': '+7-999-123-45-67', 'passport': '4010 123456'}                                                            

Очевидно, что наличие в нем данных в открытом (не маскированном) виде – это проблема. Теперь посмотрим, как настроить запуск SAST-анализатора в платформе для работы с кодом GitFLic, чтобы найти потенциальную проблему еще на этапе сборки приложения:

security:semgrep_sast:                                                                                                                                                                                             

  stage: security                                                                                                                                                                                                  

  image: semgrep/semgrep:1.127.0                                                                                                                                                                                  

  script:                                                                                                                                                                                                          

  -  semgrep scan --config semgrep/pii-logging.smart.yml --sarif –output sast-report.json  --error  .                                                                                                         

  artifacts:                                                                                                                                                                                                       

    when: always                                                                                                                                                                                                   

    reports:                                                                                                                                                                                                       

      sast:                                                                                                                                                                                                        

        paths:                                                                                                                                                                                                    

          - sast-report.json                                                                                                                                                                                   

    paths:                                                                                                                                                                                                         

      - sast-report.json                                                                                                                                                                                        

    expire_in: 1 week

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

Правила, на которые опирается SAST-анализатор Semgrep, описываются в виде отдельной конфигурации:

rules:                                                                                                                                                                                                            

  - id: logging-user-object                                                                                                                                                                                    

    message: |                                                                                                                                                                                                     

      Логирование пользовательского объекта/словаря (возможная ПДн).                                                                                                                                               

      Логируйте только redact_user(...)/mask_* или удалите ПДн из логов.                                                                                                                                          

    severity: ERROR                                                                                                                                                                                                

    languages: [python]                                                                                                                                                                                            

    patterns:                                                                                                                                                                                                      

      - pattern-either:                                                                                                                                                                                                                                                                                                                                                              

          - pattern: $LOGGER.info(..., $OBJ)                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      

      # 1) Запрет user-объектов по имени переменной                                                                                                                                                       

      - metavariable-regex:                                                                                                                                                                                        

          metavariable: $OBJ                                                                                                                                                                                      

          regex: "(?i).*(user|user_record|raw_user|customer|client).*"                                                                                                                                                                                                                                                                                                                                                

      # 2) Разрешаение safe_* (редактированные переменные)                                                                                                                                                        

      - metavariable-regex:                                                                                                                                                                                        

          metavariable: $OBJ                                                                                                                                                                                      

          regex: "^(?i)(?!safe_).*$"                                                                                                                                                                                                                                                                                                                                                                                 

      # 3) Разрешение прямых вызовов redact_user(...)                                                                                                                                                               

      - pattern-not:                                                                                                                                                                                               

          pattern: $LOGGER.info(..., redact_user(...))

В случае запуска анализатора со значением переменной user_record будет сформирован отчет, содержащий сообщения вида

"text": "Логирование словаря с PIIключами (email/phone/passport/full_name/...).nЛогируйте только замаскированные значения.n"

При этом в конвейере сборки приложения в GitFlic появится предупреждение:

Чтобы устранить проблему и дать возможность конвейеру дойти до конца, необходимо привести данные переменной user_record к варианту, который будет удовлетворять настройкам анализатора. В качестве примера рассмотрим переменную user_record со значением вида

{                 

        "user_id": "123",                                                                                                                                                                                

        "full_name": "I**n P****v",                                                                                                                                                                               

        "email": "i**n.p****v@example.com",                                                                                                                                                                       

        "phone": "+79*******432",                                                                                                                                                                               

        "passport": "40** ****56",                                                                                                                                                                                

}

Переменная с маскированными данными успешно пройдет анализ, и конвейер в этом случае дойдет до конца.

Подведем итоги.

В качестве примера источника персональных данных мы взяли блок кода приложения, ответственный за логирование событий. Подобрали инструмент (SAST-анализатор Semgrep Code), способный анализировать его работу и выдавать отчеты, и посмотрели, как работает анализатор в составе конвейера сборки в GitFlic: когда возможна утечка, процесс блокируется, а если логируются маскированые данные, все успешно завершается.

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

Успешная блокировка публикации персональных данных может лечь в основу ИБ-политики в проекте или дополнить уже существующую. Даже такие, казалось бы, небольшие вещи, как использование SAST-анализаторов при сборке приложений, способны существенно снизить общее количество утечек.

Статью подготовил Антон Веретенников, старший инженер платформы «Боцман».

Группа Астра
Автор: Группа Астра
ГК «Астра» (ООО «РусБИТех-Астра») — один из лидеров российской IT-индустрии, ведущий производитель программного обеспечения, в том числе защищенных операционных систем и платформ виртуализации. Разработка флагманского продукта, ОС семейства Astra Linux, ведется с 2008 года. На сегодня в штате компании более 1000 высококвалифицированных разработчиков и специалистов технической поддержки.
Комментарии: